/*      */ package com.zimbra.cs.db;
/*      */ 
/*      */ import com.google.common.base.Strings;
/*      */ import com.google.common.base.Supplier;
/*      */ import com.google.common.collect.HashMultimap;
/*      */ import com.google.common.collect.Iterables;
/*      */ import com.google.common.collect.Multimaps;
/*      */ import com.google.common.collect.SetMultimap;
/*      */ import com.google.common.collect.Sets;
/*      */ import com.zimbra.common.localconfig.DebugConfig;
/*      */ import com.zimbra.common.service.ServiceException;
/*      */ import com.zimbra.common.util.ListUtil;
/*      */ import com.zimbra.common.util.Log;
/*      */ import com.zimbra.common.util.Pair;
/*      */ import com.zimbra.common.util.StringUtil;
/*      */ import com.zimbra.common.util.UUIDUtil;
/*      */ import com.zimbra.common.util.ZimbraLog;
/*      */ import com.zimbra.cs.account.Account;
/*      */ import com.zimbra.cs.account.Server;
/*      */ import com.zimbra.cs.imap.ImapMessage;
/*      */ import com.zimbra.cs.index.SortBy;
/*      */ import com.zimbra.cs.mailbox.CalendarItem;
/*      */ import com.zimbra.cs.mailbox.CalendarItem.CalendarMetadata;
/*      */ import com.zimbra.cs.mailbox.Conversation;
/*      */ import com.zimbra.cs.mailbox.Flag;
/*      */ import com.zimbra.cs.mailbox.Flag.FlagInfo;
/*      */ import com.zimbra.cs.mailbox.Folder;
/*      */ import com.zimbra.cs.mailbox.MailItem;
/*      */ import com.zimbra.cs.mailbox.MailItem.IndexStatus;
/*      */ import com.zimbra.cs.mailbox.MailItem.PendingDelete;
/*      */ import com.zimbra.cs.mailbox.MailItem.Type;
/*      */ import com.zimbra.cs.mailbox.MailItem.UnderlyingData;
/*      */ import com.zimbra.cs.mailbox.MailServiceException;
/*      */ import com.zimbra.cs.mailbox.Mailbox;
/*      */ import com.zimbra.cs.mailbox.Mailbox.MailboxData;
/*      */ import com.zimbra.cs.mailbox.Message;
/*      */ import com.zimbra.cs.mailbox.Metadata;
/*      */ import com.zimbra.cs.mailbox.Note;
/*      */ import com.zimbra.cs.mailbox.Tag;
/*      */ import com.zimbra.cs.mailbox.Tag.NormalizedTags;
/*      */ import com.zimbra.cs.mailbox.VirtualConversation;
/*      */ import com.zimbra.cs.mailbox.util.TagUtil;
/*      */ import com.zimbra.cs.mailbox.util.TypedIdList;
/*      */ import com.zimbra.cs.mailbox.util.TypedIdList.ItemInfo;
/*      */ import com.zimbra.cs.pop3.Pop3Message;
/*      */ import com.zimbra.cs.store.MailboxBlob;
/*      */ import com.zimbra.cs.store.MailboxBlob.MailboxBlobInfo;
/*      */ import com.zimbra.cs.store.StoreManager;
/*      */ import com.zimbra.cs.util.SpoolingCache;
/*      */ import java.io.IOException;
/*      */ import java.io.UnsupportedEncodingException;
/*      */ import java.sql.PreparedStatement;
/*      */ import java.sql.ResultSet;
/*      */ import java.sql.SQLException;
/*      */ import java.sql.Timestamp;
/*      */ import java.util.ArrayList;
/*      */ import java.util.Arrays;
/*      */ import java.util.Collection;
/*      */ import java.util.Collections;
/*      */ import java.util.Date;
/*      */ import java.util.EnumMap;
/*      */ import java.util.EnumSet;
/*      */ import java.util.GregorianCalendar;
/*      */ import java.util.HashMap;
/*      */ import java.util.HashSet;
/*      */ import java.util.Iterator;
/*      */ import java.util.List;
/*      */ import java.util.Map;
/*      */ import java.util.Map.Entry;
/*      */ import java.util.Set;
/*      */ import java.util.SortedSet;
/*      */ import java.util.TreeSet;
/*      */ import org.apache.commons.codec.DecoderException;
/*      */ import org.apache.commons.codec.EncoderException;
/*      */ import org.apache.commons.codec.net.BCodec;
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ public class DbMailItem
/*      */ {
/*      */   public static final String TABLE_MAIL_ITEM = "mail_item";
/*      */   public static final String TABLE_MAIL_ITEM_DUMPSTER = "mail_item_dumpster";
/*      */   public static final String TABLE_REVISION = "revision";
/*      */   public static final String TABLE_REVISION_DUMPSTER = "revision_dumpster";
/*      */   public static final String TABLE_APPOINTMENT = "appointment";
/*      */   public static final String TABLE_APPOINTMENT_DUMPSTER = "appointment_dumpster";
/*      */   public static final String TABLE_OPEN_CONVERSATION = "open_conversation";
/*      */   public static final String TABLE_TOMBSTONE = "tombstone";
/*      */   public static final int MAX_SENDER_LENGTH = 128;
/*      */   public static final int MAX_RECIPIENTS_LENGTH = 128;
/*      */   public static final int MAX_SUBJECT_LENGTH = 1024;
/*      */   public static final int MAX_TEXT_LENGTH = 65534;
/*      */   public static final int MAX_MEDIUMTEXT_LENGTH = 16777216;
/*  110 */   public static final String IN_THIS_MAILBOX_AND = DebugConfig.disableMailboxGroups ? "" : "mailbox_id = ? AND ";
/*  111 */   public static final String MAILBOX_ID = DebugConfig.disableMailboxGroups ? "" : "mailbox_id, ";
/*  112 */   public static final String MAILBOX_ID_VALUE = DebugConfig.disableMailboxGroups ? "" : "?, ";
/*      */   static final int RESULTS_STREAMING_MIN_ROWS = 10000;
/*      */   
/*      */   public static final int setMailboxId(PreparedStatement stmt, Mailbox mbox, int pos) throws SQLException
/*      */   {
/*  117 */     return setMailboxId(stmt, mbox.getId(), pos);
/*      */   }
/*      */   
/*      */   public static final int setMailboxId(PreparedStatement stmt, int mboxId, int pos) throws SQLException {
/*  121 */     int nextPos = pos;
/*  122 */     if (!DebugConfig.disableMailboxGroups) {
/*  123 */       stmt.setInt(nextPos++, mboxId);
/*      */     }
/*  125 */     return nextPos;
/*      */   }
/*      */   
/*      */   public void create(MailItem.UnderlyingData data) throws ServiceException {
/*  129 */     if ((data.id <= 0) || (data.folderId <= 0) || (data.parentId == 0)) {
/*  130 */       throw ServiceException.FAILURE("invalid data for DB item create", null);
/*      */     }
/*  132 */     assert (this.mailbox.isNewItemIdValid(data.id)) : "[bug 46549] illegal id for mail item";
/*  133 */     checkNamingConstraint(this.mailbox, data.folderId, data.name, data.id);
/*      */     
/*  135 */     DbPool.DbConnection conn = this.mailbox.getOperationConnection();
/*  136 */     PreparedStatement stmt = null;
/*      */     try {
/*  138 */       MailItem.Type type = MailItem.Type.of(data.type);
/*      */       
/*  140 */       stmt = conn.prepareStatement("INSERT INTO " + getMailItemTableName(this.mailbox) + "(" + MAILBOX_ID + " id, type, parent_id, folder_id, index_id, imap_id, date, size, locator, blob_digest, unread," + " flags, tag_names, sender, recipients, subject, name, metadata, mod_metadata, change_date," + " mod_content, uuid) VALUES (" + MAILBOX_ID_VALUE + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*  145 */       int pos = 1;
/*  146 */       pos = setMailboxId(stmt, this.mailbox, pos);
/*  147 */       stmt.setInt(pos++, data.id);
/*  148 */       stmt.setByte(pos++, data.type);
/*  149 */       if (data.parentId <= 0)
/*      */       {
/*  151 */         stmt.setNull(pos++, 4);
/*      */       } else {
/*  153 */         stmt.setInt(pos++, data.parentId);
/*      */       }
/*  155 */       stmt.setInt(pos++, data.folderId);
/*  156 */       if (data.indexId == MailItem.IndexStatus.NO.id()) {
/*  157 */         stmt.setNull(pos++, 4);
/*      */       } else {
/*  159 */         stmt.setInt(pos++, data.indexId);
/*      */       }
/*  161 */       if (data.imapId <= 0) {
/*  162 */         stmt.setNull(pos++, 4);
/*      */       } else {
/*  164 */         stmt.setInt(pos++, data.imapId);
/*      */       }
/*  166 */       stmt.setInt(pos++, data.date);
/*  167 */       stmt.setLong(pos++, data.size);
/*  168 */       stmt.setString(pos++, data.locator);
/*  169 */       stmt.setString(pos++, data.getBlobDigest());
/*  170 */       switch (type) {
/*      */       case MESSAGE: 
/*      */       case CHAT: 
/*      */       case FOLDER: 
/*  174 */         stmt.setInt(pos++, data.unreadCount);
/*  175 */         break;
/*      */       default: 
/*  177 */         stmt.setNull(pos++, 4);
/*      */       }
/*      */       
/*  180 */       stmt.setInt(pos++, data.getFlags());
/*  181 */       stmt.setString(pos++, DbTag.serializeTags(data.getTags()));
/*  182 */       stmt.setString(pos++, this.sender);
/*  183 */       stmt.setString(pos++, this.recipients);
/*  184 */       stmt.setString(pos++, data.getSubject());
/*  185 */       stmt.setString(pos++, data.name);
/*  186 */       stmt.setString(pos++, checkMetadataLength(data.metadata));
/*  187 */       stmt.setInt(pos++, data.modMetadata);
/*  188 */       if (data.dateChanged > 0) {
/*  189 */         stmt.setInt(pos++, data.dateChanged);
/*      */       } else {
/*  191 */         stmt.setNull(pos++, 4);
/*      */       }
/*  193 */       stmt.setInt(pos++, data.modContent);
/*  194 */       stmt.setString(pos++, data.uuid);
/*  195 */       int num = stmt.executeUpdate();
/*  196 */       if (num != 1) {
/*  197 */         throw ServiceException.FAILURE("failed to create object", null);
/*      */       }
/*      */       
/*  200 */       DbTag.storeTagReferences(this.mailbox, data.id, type, data.getFlags(), data.unreadCount > 0);
/*  201 */       DbTag.storeTagReferences(this.mailbox, data.id, type, data.getTags());
/*      */     }
/*      */     catch (SQLException e) {
/*  204 */       if (Db.errorMatches(e, Db.Error.DUPLICATE_ROW)) {
/*  205 */         throw MailServiceException.ALREADY_EXISTS(data.id, e);
/*      */       }
/*  207 */       throw ServiceException.FAILURE("Failed to create id=" + data.id + ",type=" + data.type, e);
/*      */     }
/*      */     finally {
/*  210 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   private static void checkNamingConstraint(Mailbox mbox, int folderId, String name, int modifiedItemId) throws ServiceException {
/*  215 */     if ((name == null) || (name.equals(""))) {
/*  216 */       return;
/*      */     }
/*  218 */     if ((Db.supports(Db.Capability.UNIQUE_NAME_INDEX)) && (!Db.supports(Db.Capability.CASE_SENSITIVE_COMPARISON))) {
/*  219 */       return;
/*      */     }
/*      */     
/*  222 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/*  223 */     PreparedStatement stmt = null;
/*  224 */     ResultSet rs = null;
/*      */     try {
/*  226 */       stmt = conn.prepareStatement("SELECT COUNT(*) FROM " + getMailItemTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + "folder_id = ? AND id <> ? AND " + Db.equalsSTRING("name"));
/*      */       
/*  228 */       int pos = 1;
/*  229 */       pos = setMailboxId(stmt, mbox, pos);
/*  230 */       stmt.setInt(pos++, folderId);
/*  231 */       stmt.setInt(pos++, modifiedItemId);
/*  232 */       stmt.setString(pos++, StringUtil.trimTrailingSpaces(name));
/*  233 */       rs = stmt.executeQuery();
/*  234 */       if ((!rs.next()) || (rs.getInt(1) > 0)) {
/*  235 */         throw MailServiceException.ALREADY_EXISTS(name);
/*      */       }
/*      */     } catch (SQLException e) {
/*  238 */       throw ServiceException.FAILURE("checking for naming conflicts", e);
/*      */     } finally {
/*  240 */       DbPool.closeResults(rs);
/*  241 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static String copy(MailItem item, int id, String uuid, Folder folder, int indexId, int parentId, String locator, String metadata, boolean fromDumpster) throws ServiceException
/*      */   {
/*  247 */     Mailbox mbox = item.getMailbox();
/*  248 */     String prevFolders = null;
/*  249 */     if ((id <= 0) || (folder == null) || (parentId == 0)) {
/*  250 */       throw ServiceException.FAILURE("invalid data for DB item copy", null);
/*      */     }
/*      */     
/*  253 */     checkNamingConstraint(mbox, folder.getId(), item.getName(), id);
/*      */     
/*  255 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/*  256 */     PreparedStatement stmt = null;
/*      */     try {
/*  258 */       String srcTable = getMailItemTableName(mbox, fromDumpster);
/*  259 */       String destTable = getMailItemTableName(mbox);
/*  260 */       String mailbox_id = DebugConfig.disableMailboxGroups ? "" : "mailbox_id, ";
/*  261 */       stmt = conn.prepareStatement("INSERT INTO " + destTable + "(" + mailbox_id + " id, type, parent_id, folder_id, prev_folders, index_id, imap_id, date, size, locator, blob_digest," + " unread, flags, tag_names, sender, subject, name, metadata, mod_metadata, change_date, mod_content, uuid) " + "SELECT " + MAILBOX_ID_VALUE + " ?, type, ?, ?, ?, ?, ?, date, size, ?, blob_digest, unread," + " flags, tag_names, sender, subject, name, ?, ?, ?, ?, ? FROM " + srcTable + " WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*  269 */       int pos = 1;
/*  270 */       pos = setMailboxId(stmt, mbox, pos);
/*  271 */       stmt.setInt(pos++, id);
/*  272 */       if (parentId <= 0) {
/*  273 */         stmt.setNull(pos++, 4);
/*      */       } else {
/*  275 */         stmt.setInt(pos++, parentId);
/*      */       }
/*  277 */       stmt.setInt(pos++, folder.getId());
/*  278 */       int modseq = mbox.getOperationChangeID();
/*  279 */       prevFolders = findPrevFolders(item, modseq);
/*  280 */       stmt.setString(pos++, prevFolders);
/*  281 */       if (indexId == MailItem.IndexStatus.NO.id()) {
/*  282 */         stmt.setNull(pos++, 4);
/*      */       } else {
/*  284 */         stmt.setInt(pos++, indexId);
/*      */       }
/*  286 */       stmt.setInt(pos++, id);
/*  287 */       stmt.setString(pos++, locator);
/*  288 */       stmt.setString(pos++, checkMetadataLength(metadata));
/*  289 */       stmt.setInt(pos++, modseq);
/*  290 */       stmt.setInt(pos++, mbox.getOperationTimestamp());
/*  291 */       stmt.setInt(pos++, mbox.getOperationChangeID());
/*  292 */       stmt.setString(pos++, uuid);
/*  293 */       pos = setMailboxId(stmt, mbox, pos);
/*  294 */       stmt.setInt(pos++, item.getId());
/*  295 */       int num = stmt.executeUpdate();
/*  296 */       if (num != 1) {
/*  297 */         throw ServiceException.FAILURE("failed to create object", null);
/*      */       }
/*      */       
/*  300 */       DbTag.storeTagReferences(mbox, id, item.getType(), item.getInternalFlagBitmask(), item.isUnread());
/*  301 */       DbTag.storeTagReferences(mbox, id, item.getType(), item.getTags());
/*      */     }
/*      */     catch (SQLException e) {
/*  304 */       if (Db.errorMatches(e, Db.Error.DUPLICATE_ROW)) {
/*  305 */         throw MailServiceException.ALREADY_EXISTS(id, e);
/*      */       }
/*  307 */       throw ServiceException.FAILURE("copying " + item.getType() + ": " + item.getId(), e);
/*      */     }
/*      */     finally {
/*  310 */       DbPool.closeStatement(stmt);
/*      */     }
/*  312 */     return prevFolders;
/*      */   }
/*      */   
/*      */   public static void copyCalendarItem(CalendarItem calItem, int newId, boolean fromDumpster) throws ServiceException
/*      */   {
/*  317 */     Mailbox mbox = calItem.getMailbox();
/*  318 */     if (newId <= 0) {
/*  319 */       throw ServiceException.FAILURE("invalid data for DB item copy", null);
/*      */     }
/*      */     
/*  322 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/*  323 */     PreparedStatement stmt = null;
/*      */     try {
/*  325 */       String mailbox_id = DebugConfig.disableMailboxGroups ? "" : "mailbox_id, ";
/*  326 */       stmt = conn.prepareStatement("INSERT INTO " + getCalendarItemTableName(mbox) + "(" + mailbox_id + " uid, item_id, start_time, end_time) " + "SELECT " + MAILBOX_ID_VALUE + " uid, ?, start_time, end_time FROM " + getCalendarItemTableName(mbox, fromDumpster) + " WHERE " + IN_THIS_MAILBOX_AND + "item_id = ?");
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*  332 */       int pos = 1;
/*  333 */       pos = setMailboxId(stmt, mbox, pos);
/*  334 */       stmt.setInt(pos++, newId);
/*  335 */       pos = setMailboxId(stmt, mbox, pos);
/*  336 */       stmt.setInt(pos++, calItem.getId());
/*  337 */       int num = stmt.executeUpdate();
/*  338 */       if (num != 1) {
/*  339 */         throw ServiceException.FAILURE("failed to create object", null);
/*      */       }
/*      */     }
/*      */     catch (SQLException e) {
/*  343 */       if (Db.errorMatches(e, Db.Error.DUPLICATE_ROW)) {
/*  344 */         throw MailServiceException.ALREADY_EXISTS(newId, e);
/*      */       }
/*  346 */       throw ServiceException.FAILURE("copying " + calItem.getType() + ": " + calItem.getId(), e);
/*      */     }
/*      */     finally {
/*  349 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void copyRevision(MailItem revision, int newId, String locator, boolean fromDumpster) throws ServiceException
/*      */   {
/*  355 */     Mailbox mbox = revision.getMailbox();
/*  356 */     if (newId <= 0) {
/*  357 */       throw ServiceException.FAILURE("invalid data for DB item copy", null);
/*      */     }
/*      */     
/*  360 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/*  361 */     PreparedStatement stmt = null;
/*      */     try {
/*  363 */       String mailbox_id = DebugConfig.disableMailboxGroups ? "" : "mailbox_id, ";
/*  364 */       stmt = conn.prepareStatement("INSERT INTO " + getRevisionTableName(mbox) + "(" + mailbox_id + " item_id, version, date, size, locator, blob_digest, name, metadata," + " mod_metadata, change_date, mod_content) " + "SELECT " + MAILBOX_ID_VALUE + " ?, version, date, size, ?, blob_digest, name, metadata," + " mod_metadata, change_date, mod_content" + " FROM " + getRevisionTableName(mbox, fromDumpster) + " WHERE " + IN_THIS_MAILBOX_AND + "item_id = ? AND version = ?");
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*  373 */       int pos = 1;
/*  374 */       pos = setMailboxId(stmt, mbox, pos);
/*  375 */       stmt.setInt(pos++, newId);
/*  376 */       stmt.setString(pos++, locator);
/*  377 */       pos = setMailboxId(stmt, mbox, pos);
/*  378 */       stmt.setInt(pos++, revision.getId());
/*  379 */       stmt.setInt(pos++, revision.getVersion());
/*  380 */       int num = stmt.executeUpdate();
/*  381 */       if (num != 1) {
/*  382 */         throw ServiceException.FAILURE("failed to create object", null);
/*      */       }
/*      */     }
/*      */     catch (SQLException e) {
/*  386 */       if (Db.errorMatches(e, Db.Error.DUPLICATE_ROW)) {
/*  387 */         throw MailServiceException.ALREADY_EXISTS(newId, e);
/*      */       }
/*  389 */       throw ServiceException.FAILURE("copying revision " + revision.getVersion() + " for " + revision.getType() + ": " + revision.getId(), e);
/*      */     }
/*      */     finally
/*      */     {
/*  393 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void icopy(MailItem source, MailItem.UnderlyingData data, boolean shared) throws ServiceException {
/*  398 */     Mailbox mbox = source.getMailbox();
/*  399 */     if ((data == null) || (data.id <= 0) || (data.folderId <= 0) || (data.parentId == 0)) {
/*  400 */       throw ServiceException.FAILURE("invalid data for DB item i-copy", null);
/*      */     }
/*  402 */     checkNamingConstraint(mbox, data.folderId, source.getName(), data.id);
/*      */     
/*  404 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/*  405 */     PreparedStatement stmt = null;
/*      */     try {
/*  407 */       String table = getMailItemTableName(mbox);
/*  408 */       String mailbox_id = DebugConfig.disableMailboxGroups ? "" : "mailbox_id, ";
/*      */       String flags;
/*  410 */       String flags; if (!shared) {
/*  411 */         flags = "flags"; } else { String flags;
/*  412 */         if (Db.supports(Db.Capability.BITWISE_OPERATIONS)) {
/*  413 */           flags = "flags | " + Flag.BITMASK_COPIED;
/*      */         } else {
/*  415 */           flags = "CASE WHEN " + Db.getInstance().bitAND("flags", String.valueOf(Flag.BITMASK_COPIED)) + " <> 0 THEN flags ELSE flags + " + Flag.BITMASK_COPIED + " END";
/*      */         }
/*      */       }
/*  418 */       stmt = conn.prepareStatement("INSERT INTO " + table + "(" + mailbox_id + " id, type, parent_id, folder_id, prev_folders, index_id, imap_id, date, size, locator, blob_digest," + " unread, flags, tag_names, sender, subject, name, metadata, mod_metadata, change_date, mod_content) " + "SELECT " + mailbox_id + " ?, type, parent_id, ?, ?, ?, ?, date, size, ?, blob_digest," + " unread, " + flags + ", tag_names, sender, subject, name, metadata, ?, ?, ? FROM " + table + " WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*  426 */       int pos = 1;
/*  427 */       stmt.setInt(pos++, data.id);
/*  428 */       stmt.setInt(pos++, data.folderId);
/*  429 */       stmt.setString(pos++, data.getPrevFolders());
/*  430 */       if (data.indexId == MailItem.IndexStatus.NO.id()) {
/*  431 */         stmt.setNull(pos++, 4);
/*      */       } else {
/*  433 */         stmt.setInt(pos++, data.indexId);
/*      */       }
/*  435 */       stmt.setInt(pos++, data.imapId);
/*  436 */       stmt.setString(pos++, data.locator);
/*  437 */       stmt.setInt(pos++, mbox.getOperationChangeID());
/*  438 */       stmt.setInt(pos++, mbox.getOperationTimestamp());
/*  439 */       stmt.setInt(pos++, mbox.getOperationChangeID());
/*  440 */       pos = setMailboxId(stmt, mbox, pos);
/*  441 */       stmt.setInt(pos++, source.getId());
/*  442 */       stmt.executeUpdate();
/*  443 */       stmt.close();
/*      */       
/*  445 */       boolean needsTag = (shared) && (!source.isTagged(Flag.FlagInfo.COPIED));
/*      */       
/*  447 */       if ((needsTag) || (source.getParentId() > 0)) {
/*  448 */         boolean altersMODSEQ = source.getParentId() > 0;
/*  449 */         String updateChangeID = altersMODSEQ ? ", mod_metadata = ?, change_date = ?" : "";
/*  450 */         stmt = conn.prepareStatement("UPDATE " + table + " SET parent_id = NULL, flags = " + flags + updateChangeID + " WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */         
/*      */ 
/*  453 */         pos = 1;
/*  454 */         if (altersMODSEQ) {
/*  455 */           stmt.setInt(pos++, mbox.getOperationChangeID());
/*  456 */           stmt.setInt(pos++, mbox.getOperationTimestamp());
/*      */         }
/*  458 */         pos = setMailboxId(stmt, mbox, pos);
/*  459 */         stmt.setInt(pos++, source.getId());
/*  460 */         stmt.executeUpdate();
/*  461 */         stmt.close();
/*      */       }
/*      */       
/*  464 */       if (((source instanceof Message)) && (source.getParentId() <= 0)) {
/*  465 */         changeOpenTargets(source, data.id);
/*      */       }
/*      */       
/*  468 */       MailItem.Type type = MailItem.Type.of(data.type);
/*  469 */       DbTag.storeTagReferences(mbox, data.id, type, data.getFlags() | (shared ? Flag.BITMASK_COPIED : 0), data.unreadCount > 0);
/*  470 */       DbTag.storeTagReferences(mbox, data.id, type, data.getTags());
/*      */     }
/*      */     catch (SQLException e) {
/*  473 */       if (Db.errorMatches(e, Db.Error.DUPLICATE_ROW)) {
/*  474 */         throw MailServiceException.ALREADY_EXISTS(data.id, e);
/*      */       }
/*  476 */       throw ServiceException.FAILURE("i-copying " + source.getType() + ": " + source.getId(), e);
/*      */     }
/*      */     finally {
/*  479 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void snapshotRevision(MailItem item, int version) throws ServiceException {
/*  484 */     Mailbox mbox = item.getMailbox();
/*      */     
/*  486 */     assert (version >= 1);
/*      */     
/*  488 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/*  489 */     PreparedStatement stmt = null;
/*      */     try {
/*  491 */       String command = Db.supports(Db.Capability.REPLACE_INTO) ? "REPLACE" : "INSERT";
/*  492 */       String mailbox_id = DebugConfig.disableMailboxGroups ? "" : "mailbox_id, ";
/*  493 */       stmt = conn.prepareStatement(command + " INTO " + getRevisionTableName(mbox) + "(" + mailbox_id + "item_id, version, date, size, locator, blob_digest," + " name, metadata, mod_metadata, change_date, mod_content) " + "SELECT " + mailbox_id + "id, ?, date, size, locator, blob_digest," + " name, metadata, mod_metadata, change_date, mod_content" + " FROM " + getMailItemTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*  500 */       int pos = 1;
/*  501 */       stmt.setInt(pos++, version);
/*  502 */       pos = setMailboxId(stmt, mbox, pos);
/*  503 */       stmt.setInt(pos++, item.getId());
/*  504 */       stmt.executeUpdate();
/*      */     }
/*      */     catch (SQLException e) {
/*  507 */       if (Db.errorMatches(e, Db.Error.DUPLICATE_ROW)) {
/*  508 */         throw MailServiceException.ALREADY_EXISTS(item.getId(), e);
/*      */       }
/*  510 */       throw ServiceException.FAILURE("saving revision info for " + item.getType() + ": " + item.getId(), e);
/*      */     }
/*      */     finally {
/*  513 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void purgeRevisions(MailItem item, int revision, boolean includeOlderRevisions) throws ServiceException {
/*  518 */     if (revision <= 0) {
/*  519 */       return;
/*      */     }
/*      */     
/*  522 */     Mailbox mbox = item.getMailbox();
/*  523 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/*  524 */     PreparedStatement stmt = null;
/*      */     try {
/*  526 */       stmt = conn.prepareStatement("DELETE FROM " + getRevisionTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + "item_id = ? AND version " + (includeOlderRevisions ? "<= ?" : "= ?"));
/*      */       
/*      */ 
/*  529 */       int pos = 1;
/*  530 */       pos = setMailboxId(stmt, mbox, pos);
/*  531 */       stmt.setInt(pos++, item.getId());
/*  532 */       stmt.setInt(pos++, revision);
/*  533 */       stmt.executeUpdate();
/*      */     } catch (SQLException e) {
/*  535 */       throw ServiceException.FAILURE("purging revisions for " + item.getType() + ": " + item.getId(), e);
/*      */     } finally {
/*  537 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void changeType(MailItem item, byte type) throws ServiceException {
/*  542 */     Mailbox mbox = item.getMailbox();
/*      */     
/*  544 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/*  545 */     PreparedStatement stmt = null;
/*      */     try {
/*  547 */       stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(item) + " SET type = ? WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */       
/*  549 */       int pos = 1;
/*  550 */       stmt.setInt(pos++, type);
/*  551 */       pos = setMailboxId(stmt, mbox, pos);
/*  552 */       stmt.setInt(pos++, item.getId());
/*  553 */       stmt.executeUpdate();
/*      */     } catch (SQLException e) {
/*  555 */       throw ServiceException.FAILURE("writing new type for item " + item.getId(), e);
/*      */     } finally {
/*  557 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void setFolder(MailItem item, Folder folder) throws ServiceException {
/*  562 */     Mailbox mbox = item.getMailbox();
/*  563 */     if (mbox != folder.getMailbox()) {
/*  564 */       throw MailServiceException.WRONG_MAILBOX();
/*      */     }
/*  566 */     checkNamingConstraint(mbox, folder.getId(), item.getName(), item.getId());
/*      */     
/*  568 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/*  569 */     PreparedStatement stmt = null;
/*      */     try {
/*  571 */       String imapRenumber = mbox.isTrackingImap() ? ", imap_id = CASE WHEN imap_id IS NULL THEN NULL ELSE 0 END" : "";
/*  572 */       int pos = 1;
/*  573 */       boolean hasIndexId = false;
/*  574 */       if ((item instanceof Folder)) {
/*  575 */         stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(item) + " SET parent_id = ?, folder_id = ?, prev_folders = ?, mod_metadata = ?, change_date = ?" + " WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */         
/*      */ 
/*  578 */         stmt.setInt(pos++, folder.getId());
/*  579 */       } else if (((item instanceof Conversation)) && (!(item instanceof VirtualConversation))) {
/*  580 */         stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(item) + " SET folder_id = ?, prev_folders = ?, mod_metadata = ?, change_date = ?" + imapRenumber + " WHERE " + IN_THIS_MAILBOX_AND + "parent_id = ?");
/*      */ 
/*      */       }
/*      */       else
/*      */       {
/*  585 */         hasIndexId = true;
/*  586 */         stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(item) + " SET folder_id = ?, prev_folders = ?, index_id = ?, mod_metadata = ?, change_date = ? " + imapRenumber + " WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */       }
/*      */       
/*      */ 
/*  590 */       stmt.setInt(pos++, folder.getId());
/*  591 */       int modseq = mbox.getOperationChangeID();
/*  592 */       String prevFolders = findPrevFolders(item, modseq);
/*  593 */       stmt.setString(pos++, prevFolders);
/*  594 */       item.getUnderlyingData().setPrevFolders(prevFolders);
/*  595 */       if (hasIndexId) {
/*  596 */         if (item.getIndexStatus() == MailItem.IndexStatus.NO) {
/*  597 */           stmt.setNull(pos++, 4);
/*      */         } else {
/*  599 */           stmt.setInt(pos++, item.getIndexId());
/*      */         }
/*      */       }
/*  602 */       stmt.setInt(pos++, modseq);
/*  603 */       stmt.setInt(pos++, mbox.getOperationTimestamp());
/*  604 */       pos = setMailboxId(stmt, mbox, pos);
/*  605 */       stmt.setInt(pos++, (item instanceof VirtualConversation) ? ((VirtualConversation)item).getMessageId() : item.getId());
/*  606 */       stmt.executeUpdate();
/*      */     }
/*      */     catch (SQLException e) {
/*  609 */       if (Db.errorMatches(e, Db.Error.DUPLICATE_ROW)) {
/*  610 */         throw MailServiceException.ALREADY_EXISTS(item.getName(), e);
/*      */       }
/*  612 */       throw ServiceException.FAILURE("writing new folder data for item " + item.getId(), e);
/*      */     }
/*      */     finally {
/*  615 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   private static String findPrevFolders(MailItem item, int modseq)
/*      */     throws ServiceException
/*      */   {
/*  622 */     Mailbox mbox = item.getMailbox();
/*  623 */     String prevFolders = item.getPrevFolders();
/*  624 */     if (!StringUtil.isNullOrEmpty(prevFolders)) {
/*  625 */       String[] modseq2FolderId = prevFolders.split(";");
/*  626 */       int maxCount = mbox.getAccount().getServer().getPrevFoldersToTrackMax();
/*  627 */       if (modseq2FolderId.length < maxCount) {
/*  628 */         prevFolders = prevFolders + ";" + modseq + ":" + item.getFolderId();
/*      */       }
/*      */       else {
/*  631 */         String[] tmp = new String[maxCount];
/*  632 */         System.arraycopy(modseq2FolderId, 1, tmp, 0, maxCount - 1);
/*  633 */         tmp[(maxCount - 1)] = (modseq + ":" + item.getFolderId());
/*  634 */         prevFolders = StringUtil.join(";", tmp);
/*      */       }
/*      */     } else {
/*  637 */       prevFolders = modseq + ":" + item.getFolderId();
/*      */     }
/*  639 */     return prevFolders;
/*      */   }
/*      */   
/*      */   public static void setFolder(List<Message> msgs, Folder folder) throws ServiceException {
/*  643 */     if ((msgs == null) || (msgs.isEmpty())) {
/*  644 */       return;
/*      */     }
/*  646 */     Mailbox mbox = folder.getMailbox();
/*  647 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/*  648 */     PreparedStatement stmt = null;
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     try
/*      */     {
/*  671 */       int count = 0;
/*  672 */       int batchSize = 500;
/*  673 */       String imapRenumber = mbox.isTrackingImap() ? ", imap_id = CASE WHEN imap_id IS NULL THEN NULL ELSE 0 END" : "";
/*  674 */       stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(folder) + " SET folder_id = ?, prev_folders=?, mod_metadata = ?, change_date = ?" + imapRenumber + " WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */       
/*      */ 
/*  677 */       int modseq = mbox.getOperationChangeID();
/*  678 */       for (int j = 0; j < msgs.size(); j++) {
/*  679 */         int pos = 1;
/*  680 */         stmt.setInt(pos++, folder.getId());
/*  681 */         MailItem.UnderlyingData ud = ((Message)msgs.get(j)).getUnderlyingData();
/*      */         
/*  683 */         if (((Message)msgs.get(j)).getFolderId() != folder.getId()) {
/*  684 */           String prevFolders = ud.getPrevFolders();
/*  685 */           if (!StringUtil.isNullOrEmpty(prevFolders)) {
/*  686 */             String[] modseq2FolderId = prevFolders.split(";");
/*  687 */             int maxCount = mbox.getAccount().getServer().getPrevFoldersToTrackMax();
/*  688 */             if (modseq2FolderId.length < maxCount) {
/*  689 */               prevFolders = prevFolders + ";" + modseq + ":" + ud.folderId;
/*      */             }
/*      */             else {
/*  692 */               String[] tmp = new String[maxCount];
/*  693 */               System.arraycopy(modseq2FolderId, 1, tmp, 0, maxCount - 1);
/*  694 */               tmp[(maxCount - 1)] = (modseq + ":" + ud.folderId);
/*  695 */               prevFolders = StringUtil.join(";", tmp);
/*      */             }
/*      */           } else {
/*  698 */             prevFolders = modseq + ":" + ud.folderId;
/*      */           }
/*  700 */           stmt.setString(pos++, prevFolders);
/*  701 */           ud.setPrevFolders(prevFolders);
/*      */         } else {
/*  703 */           stmt.setString(pos++, ((Message)msgs.get(j)).getUnderlyingData().getPrevFolders());
/*      */         }
/*  705 */         stmt.setInt(pos++, modseq);
/*  706 */         stmt.setInt(pos++, mbox.getOperationTimestamp());
/*  707 */         pos = setMailboxId(stmt, mbox, pos);
/*  708 */         stmt.setInt(pos++, ((Message)msgs.get(j)).getId());
/*  709 */         stmt.addBatch();
/*  710 */         count++; if (count % batchSize == 0) {
/*  711 */           stmt.executeBatch();
/*      */         }
/*      */       }
/*  714 */       stmt.executeBatch();
/*  715 */       stmt.close();
/*  716 */       stmt = null;
/*      */ 
/*      */     }
/*      */     catch (SQLException e)
/*      */     {
/*      */ 
/*  722 */       throw ServiceException.FAILURE("writing new folder data for messages", e);
/*      */     } finally {
/*  724 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static SetMultimap<MailItem.Type, Integer> getIndexDeferredIds(DbPool.DbConnection conn, Mailbox mbox) throws ServiceException
/*      */   {
/*  730 */     SetMultimap<MailItem.Type, Integer> result = Multimaps.newSetMultimap(new EnumMap(MailItem.Type.class), new Supplier()
/*      */     {
/*      */ 
/*      */       public Set<Integer> get()
/*      */       {
/*  735 */         return new HashSet();
/*      */       }
/*      */       
/*  738 */     });
/*  739 */     PreparedStatement stmt = null;
/*  740 */     ResultSet rs = null;
/*      */     try {
/*  742 */       stmt = conn.prepareStatement("SELECT type, id FROM " + getMailItemTableName(mbox, false) + " WHERE " + IN_THIS_MAILBOX_AND + "index_id <= 1");
/*      */       
/*  744 */       setMailboxId(stmt, mbox, 1);
/*  745 */       rs = stmt.executeQuery();
/*  746 */       while (rs.next()) {
/*  747 */         result.put(MailItem.Type.of(rs.getByte(1)), Integer.valueOf(rs.getInt(2)));
/*      */       }
/*      */     } catch (SQLException e) {
/*  750 */       throw ServiceException.FAILURE("Failed to query index deferred IDs", e);
/*      */     } finally {
/*  752 */       conn.closeQuietly(rs);
/*  753 */       conn.closeQuietly(stmt);
/*      */     }
/*      */     
/*  756 */     if (mbox.dumpsterEnabled()) {
/*      */       try {
/*  758 */         stmt = conn.prepareStatement("SELECT type, id FROM " + getMailItemTableName(mbox, true) + " WHERE " + IN_THIS_MAILBOX_AND + "index_id <= 1");
/*      */         
/*  760 */         setMailboxId(stmt, mbox, 1);
/*  761 */         rs = stmt.executeQuery();
/*  762 */         while (rs.next()) {
/*  763 */           result.put(MailItem.Type.of(rs.getByte(1)), Integer.valueOf(rs.getInt(2)));
/*      */         }
/*      */       } catch (SQLException e) {
/*  766 */         throw ServiceException.FAILURE("Failed to query index deferred IDs from dumpster", e);
/*      */       } finally {
/*  768 */         conn.closeQuietly(rs);
/*  769 */         conn.closeQuietly(stmt);
/*      */       }
/*      */     }
/*  772 */     return result;
/*      */   }
/*      */   
/*      */   public static List<Integer> getReIndexIds(DbPool.DbConnection conn, Mailbox mbox, Set<MailItem.Type> types) throws ServiceException
/*      */   {
/*  777 */     List<Integer> ids = new ArrayList();
/*  778 */     PreparedStatement stmt = null;
/*  779 */     ResultSet rs = null;
/*      */     try {
/*  781 */       stmt = conn.prepareStatement("SELECT id FROM " + getMailItemTableName(mbox, false) + " WHERE " + IN_THIS_MAILBOX_AND + "index_id IS NOT NULL" + (types.isEmpty() ? "" : new StringBuilder().append(" AND ").append(DbUtil.whereIn("type", types.size())).toString()));
/*      */       
/*      */ 
/*  784 */       int pos = setMailboxId(stmt, mbox, 1);
/*  785 */       for (MailItem.Type type : types) {
/*  786 */         stmt.setByte(pos++, type.toByte());
/*      */       }
/*  788 */       rs = stmt.executeQuery();
/*  789 */       while (rs.next()) {
/*  790 */         ids.add(Integer.valueOf(rs.getInt(1)));
/*      */       }
/*      */     } catch (SQLException e) {
/*  793 */       throw ServiceException.FAILURE("Failed to query re-index IDs", e);
/*      */     } finally {
/*  795 */       conn.closeQuietly(rs);
/*  796 */       conn.closeQuietly(stmt);
/*      */     }
/*  798 */     if (mbox.dumpsterEnabled()) {
/*      */       try {
/*  800 */         stmt = conn.prepareStatement("SELECT id FROM " + getMailItemTableName(mbox, true) + " WHERE " + IN_THIS_MAILBOX_AND + "index_id IS NOT NULL" + (types.isEmpty() ? "" : new StringBuilder().append(" AND ").append(DbUtil.whereIn("type", types.size())).toString()));
/*      */         
/*      */ 
/*  803 */         int pos = setMailboxId(stmt, mbox, 1);
/*  804 */         for (MailItem.Type type : types) {
/*  805 */           stmt.setByte(pos++, type.toByte());
/*      */         }
/*  807 */         rs = stmt.executeQuery();
/*  808 */         while (rs.next()) {
/*  809 */           ids.add(Integer.valueOf(rs.getInt(1)));
/*      */         }
/*      */       } catch (SQLException e) {
/*  812 */         throw ServiceException.FAILURE("Failed to query re-index IDs from dumpster", e);
/*      */       } finally {
/*  814 */         conn.closeQuietly(rs);
/*  815 */         conn.closeQuietly(stmt);
/*      */       }
/*      */     }
/*  818 */     return ids;
/*      */   }
/*      */   
/*      */   public static void setIndexIds(DbPool.DbConnection conn, Mailbox mbox, List<Integer> ids) throws ServiceException {
/*  822 */     if (ids.isEmpty()) {
/*  823 */       return;
/*      */     }
/*  825 */     for (int i = 0; i < ids.size(); i += Db.getINClauseBatchSize()) {
/*  826 */       int count = Math.min(Db.getINClauseBatchSize(), ids.size() - i);
/*      */       
/*  828 */       PreparedStatement stmt = null;
/*      */       int updated;
/*  830 */       try { stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(mbox, false) + " SET index_id = id WHERE " + IN_THIS_MAILBOX_AND + DbUtil.whereIn("id", count));
/*      */         
/*  832 */         int pos = setMailboxId(stmt, mbox, 1);
/*  833 */         for (int j = i; j < i + count; j++) {
/*  834 */           stmt.setInt(pos++, ((Integer)ids.get(j)).intValue());
/*      */         }
/*  836 */         updated = stmt.executeUpdate();
/*      */       } catch (SQLException e) {
/*  838 */         throw ServiceException.FAILURE("Failed to set index_id", e);
/*      */       } finally {
/*  840 */         conn.closeQuietly(stmt);
/*      */       }
/*  842 */       if (updated != count)
/*      */       {
/*      */ 
/*  845 */         if (mbox.dumpsterEnabled())
/*      */           try {
/*  847 */             stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(mbox, true) + " SET index_id = id WHERE " + IN_THIS_MAILBOX_AND + DbUtil.whereIn("id", count));
/*      */             
/*  849 */             int pos = setMailboxId(stmt, mbox, 1);
/*  850 */             for (int j = i; j < i + count; j++) {
/*  851 */               stmt.setInt(pos++, ((Integer)ids.get(j)).intValue());
/*      */             }
/*  853 */             stmt.executeUpdate();
/*      */           } catch (SQLException e) {
/*  855 */             throw ServiceException.FAILURE("Failed to set index_id in dumpster", e);
/*      */           } finally {
/*  857 */             conn.closeQuietly(stmt);
/*      */           }
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */   public static void resetIndexId(DbPool.DbConnection conn, Mailbox mbox) throws ServiceException {
/*  864 */     PreparedStatement stmt = null;
/*      */     try {
/*  866 */       stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(mbox, false) + " SET index_id = 0 WHERE " + IN_THIS_MAILBOX_AND + "index_id > 0");
/*      */       
/*  868 */       setMailboxId(stmt, mbox, 1);
/*  869 */       stmt.executeUpdate();
/*      */     } catch (SQLException e) {
/*  871 */       throw ServiceException.FAILURE("Failed to reset index_id", e);
/*      */     } finally {
/*  873 */       conn.closeQuietly(stmt);
/*      */     }
/*  875 */     if (mbox.dumpsterEnabled()) {
/*      */       try {
/*  877 */         stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(mbox, true) + " SET index_id = 0 WHERE " + IN_THIS_MAILBOX_AND + "index_id > 0");
/*      */         
/*  879 */         setMailboxId(stmt, mbox, 1);
/*  880 */         stmt.executeUpdate();
/*      */       } catch (SQLException e) {
/*  882 */         throw ServiceException.FAILURE("Failed to reset index_id in dumpster", e);
/*      */       } finally {
/*  884 */         conn.closeQuietly(stmt);
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */   public static void setParent(MailItem child, MailItem parent) throws ServiceException {
/*  890 */     setParent(new MailItem[] { child }, parent);
/*      */   }
/*      */   
/*      */   public static void setParent(MailItem[] children, MailItem parent) throws ServiceException {
/*  894 */     if ((children == null) || (children.length == 0)) {
/*  895 */       return;
/*      */     }
/*  897 */     Mailbox mbox = children[0].getMailbox();
/*  898 */     if ((parent != null) && (mbox != parent.getMailbox())) {
/*  899 */       throw MailServiceException.WRONG_MAILBOX();
/*      */     }
/*  901 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/*  902 */     PreparedStatement stmt = null;
/*      */     try {
/*  904 */       for (int i = 0; i < children.length; i += Db.getINClauseBatchSize()) {
/*  905 */         int count = Math.min(Db.getINClauseBatchSize(), children.length - i);
/*  906 */         stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(mbox) + " SET parent_id = ?, mod_metadata = ?, change_date = ?" + " WHERE " + IN_THIS_MAILBOX_AND + DbUtil.whereIn("id", count));
/*      */         
/*      */ 
/*  909 */         int pos = 1;
/*  910 */         if ((parent == null) || ((parent instanceof VirtualConversation))) {
/*  911 */           stmt.setNull(pos++, 4);
/*      */         } else {
/*  913 */           stmt.setInt(pos++, parent.getId());
/*      */         }
/*  915 */         stmt.setInt(pos++, mbox.getOperationChangeID());
/*  916 */         stmt.setInt(pos++, mbox.getOperationTimestamp());
/*  917 */         pos = setMailboxId(stmt, mbox, pos);
/*  918 */         for (int index = i; index < i + count; index++) {
/*  919 */           stmt.setInt(pos++, children[index].getId());
/*      */         }
/*  921 */         stmt.executeUpdate();
/*  922 */         stmt.close();
/*  923 */         stmt = null;
/*      */       }
/*      */     } catch (SQLException e) {
/*  926 */       throw ServiceException.FAILURE("adding children to parent " + (parent == null ? "NULL" : new StringBuilder().append(parent.getId()).append("").toString()), e);
/*      */     } finally {
/*  928 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void reparentChildren(MailItem oldParent, MailItem newParent) throws ServiceException {
/*  933 */     if (oldParent == newParent) {
/*  934 */       return;
/*      */     }
/*  936 */     Mailbox mbox = oldParent.getMailbox();
/*  937 */     if (mbox != newParent.getMailbox()) {
/*  938 */       throw MailServiceException.WRONG_MAILBOX();
/*      */     }
/*  940 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/*  941 */     PreparedStatement stmt = null;
/*      */     try {
/*  943 */       String relation = (oldParent instanceof VirtualConversation) ? "id = ?" : "parent_id = ?";
/*      */       
/*  945 */       stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(oldParent) + " SET parent_id = ?, mod_metadata = ?, change_date = ?" + " WHERE " + IN_THIS_MAILBOX_AND + relation);
/*      */       
/*      */ 
/*  948 */       int pos = 1;
/*  949 */       if ((newParent instanceof VirtualConversation)) {
/*  950 */         stmt.setNull(pos++, 4);
/*      */       } else {
/*  952 */         stmt.setInt(pos++, newParent.getId());
/*      */       }
/*  954 */       stmt.setInt(pos++, mbox.getOperationChangeID());
/*  955 */       stmt.setInt(pos++, mbox.getOperationTimestamp());
/*  956 */       pos = setMailboxId(stmt, mbox, pos);
/*  957 */       stmt.setInt(pos++, (oldParent instanceof VirtualConversation) ? ((VirtualConversation)oldParent).getMessageId() : oldParent.getId());
/*  958 */       stmt.executeUpdate();
/*      */     } catch (SQLException e) {
/*  960 */       throw ServiceException.FAILURE("writing new parent for children of item " + oldParent.getId(), e);
/*      */     } finally {
/*  962 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void saveMetadata(MailItem item, String metadata) throws ServiceException {
/*  967 */     Mailbox mbox = item.getMailbox();
/*  968 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/*  969 */     PreparedStatement stmt = null;
/*      */     try {
/*  971 */       stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(item) + " SET date = ?, size = ?, metadata = ?, mod_metadata = ?, change_date = ?, mod_content = ?" + " WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */       
/*      */ 
/*  974 */       int pos = 1;
/*  975 */       stmt.setInt(pos++, (int)(item.getDate() / 1000L));
/*  976 */       stmt.setLong(pos++, item.getSize());
/*  977 */       stmt.setString(pos++, checkMetadataLength(metadata));
/*  978 */       stmt.setInt(pos++, mbox.getOperationChangeID());
/*  979 */       stmt.setInt(pos++, mbox.getOperationTimestamp());
/*  980 */       stmt.setInt(pos++, item.getSavedSequence());
/*  981 */       pos = setMailboxId(stmt, mbox, pos);
/*  982 */       stmt.setInt(pos++, item.getId());
/*  983 */       stmt.executeUpdate();
/*      */     } catch (SQLException e) {
/*  985 */       throw ServiceException.FAILURE("writing metadata for mailbox " + item.getMailboxId() + ", item " + item.getId(), e);
/*      */     } finally {
/*  987 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void persistCounts(MailItem item, Metadata metadata) throws ServiceException {
/*  992 */     Mailbox mbox = item.getMailbox();
/*  993 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/*  994 */     PreparedStatement stmt = null;
/*      */     try {
/*  996 */       stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(item) + " SET size = ?, unread = ?, metadata = ?, mod_metadata = ?, change_date = ?, mod_content = ?" + " WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */       
/*      */ 
/*  999 */       int pos = 1;
/* 1000 */       stmt.setLong(pos++, item.getSize());
/* 1001 */       stmt.setInt(pos++, item.getUnreadCount());
/* 1002 */       stmt.setString(pos++, checkMetadataLength(metadata.toString()));
/* 1003 */       stmt.setInt(pos++, item.getModifiedSequence());
/* 1004 */       if (item.getChangeDate() > 0L) {
/* 1005 */         stmt.setInt(pos++, (int)(item.getChangeDate() / 1000L));
/*      */       } else {
/* 1007 */         stmt.setNull(pos++, 4);
/*      */       }
/* 1009 */       stmt.setInt(pos++, item.getSavedSequence());
/* 1010 */       pos = setMailboxId(stmt, mbox, pos);
/* 1011 */       stmt.setInt(pos++, item.getId());
/* 1012 */       stmt.executeUpdate();
/*      */     } catch (SQLException e) {
/* 1014 */       throw ServiceException.FAILURE("writing metadata for mailbox " + item.getMailboxId() + ", item " + item.getId(), e);
/*      */     } finally {
/* 1016 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void saveSubject(Note note) throws ServiceException
/*      */   {
/* 1022 */     Mailbox mbox = note.getMailbox();
/* 1023 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 1024 */     PreparedStatement stmt = null;
/*      */     try {
/* 1026 */       stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(note) + " SET date = ?, size = ?, subject = ?, mod_metadata = ?, change_date = ?, mod_content = ?" + " WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */       
/*      */ 
/* 1029 */       int pos = 1;
/* 1030 */       stmt.setInt(pos++, (int)(note.getDate() / 1000L));
/* 1031 */       stmt.setLong(pos++, note.getSize());
/* 1032 */       stmt.setString(pos++, note.getSubject());
/* 1033 */       stmt.setInt(pos++, mbox.getOperationChangeID());
/* 1034 */       stmt.setInt(pos++, mbox.getOperationTimestamp());
/* 1035 */       stmt.setInt(pos++, mbox.getOperationChangeID());
/* 1036 */       pos = setMailboxId(stmt, mbox, pos);
/* 1037 */       stmt.setInt(pos++, note.getId());
/* 1038 */       stmt.executeUpdate();
/*      */     } catch (SQLException e) {
/* 1040 */       throw ServiceException.FAILURE("writing subject for mailbox " + note.getMailboxId() + ", note " + note.getId(), e);
/*      */     } finally {
/* 1042 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void saveName(MailItem item, int folderId, Metadata metadata) throws ServiceException {
/* 1047 */     Mailbox mbox = item.getMailbox();
/* 1048 */     String name = item.getName().isEmpty() ? null : item.getName();
/* 1049 */     checkNamingConstraint(mbox, folderId, name, item.getId());
/*      */     
/* 1051 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 1052 */     PreparedStatement stmt = null;
/*      */     try {
/* 1054 */       boolean isFolder = item instanceof Folder;
/* 1055 */       stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(item) + " SET date = ?, size = ?, flags = ?, name = ?, subject = ?," + "  folder_id = ?," + (isFolder ? " parent_id = ?," : "") + "  metadata = ?, mod_metadata = ?, change_date = ?" + " WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */       
/*      */ 
/*      */ 
/*      */ 
/* 1060 */       int pos = 1;
/* 1061 */       stmt.setInt(pos++, (int)(item.getDate() / 1000L));
/* 1062 */       stmt.setLong(pos++, item.getSize());
/* 1063 */       stmt.setLong(pos++, item.getInternalFlagBitmask());
/* 1064 */       stmt.setString(pos++, name);
/* 1065 */       stmt.setString(pos++, name);
/* 1066 */       stmt.setInt(pos++, folderId);
/* 1067 */       if (isFolder) {
/* 1068 */         stmt.setInt(pos++, folderId);
/*      */       }
/* 1070 */       stmt.setString(pos++, metadata.toString());
/* 1071 */       stmt.setInt(pos++, mbox.getOperationChangeID());
/* 1072 */       stmt.setInt(pos++, mbox.getOperationTimestamp());
/* 1073 */       pos = setMailboxId(stmt, mbox, pos);
/* 1074 */       stmt.setInt(pos++, item.getId());
/* 1075 */       stmt.executeUpdate();
/*      */       
/* 1077 */       if (mbox.isItemModified(item, 4)) {
/* 1078 */         DbTag.updateTagReferences(mbox, item.getId(), item.getType(), item.getInternalFlagBitmask(), item.isUnread(), item.getTags());
/*      */       }
/*      */     }
/*      */     catch (SQLException e)
/*      */     {
/* 1083 */       if (Db.errorMatches(e, Db.Error.DUPLICATE_ROW)) {
/* 1084 */         throw MailServiceException.ALREADY_EXISTS(name, e);
/*      */       }
/* 1086 */       throw ServiceException.FAILURE("writing name for mailbox " + item.getMailboxId() + ", item " + item.getId(), e);
/*      */     }
/*      */     finally {
/* 1089 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public void update(MailItem item, Metadata metadata) throws ServiceException {
/* 1094 */     String name = item.getName().isEmpty() ? null : item.getName();
/* 1095 */     checkNamingConstraint(this.mailbox, item.getFolderId(), name, item.getId());
/*      */     
/* 1097 */     DbPool.DbConnection conn = this.mailbox.getOperationConnection();
/* 1098 */     PreparedStatement stmt = null;
/*      */     try {
/* 1100 */       stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(item) + " SET type = ?, imap_id = ?, index_id = ?, parent_id = ?, date = ?, size = ?, flags = ?," + "  blob_digest = ?, sender = ?, recipients = ?, subject = ?, name = ?," + "  metadata = ?, mod_metadata = ?, change_date = ?, mod_content = ?, locator = ?" + " WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */       
/*      */ 
/*      */ 
/*      */ 
/* 1105 */       int pos = 1;
/* 1106 */       stmt.setByte(pos++, item.getType().toByte());
/* 1107 */       if (item.getImapUid() >= 0) {
/* 1108 */         stmt.setInt(pos++, item.getImapUid());
/*      */       } else {
/* 1110 */         stmt.setNull(pos++, 4);
/*      */       }
/* 1112 */       if (item.getIndexStatus() == MailItem.IndexStatus.NO) {
/* 1113 */         stmt.setNull(pos++, 4);
/*      */       } else {
/* 1115 */         stmt.setInt(pos++, item.getIndexId());
/*      */       }
/*      */       
/* 1118 */       if (item.getParentId() <= 0) {
/* 1119 */         stmt.setNull(pos++, 4);
/*      */       } else {
/* 1121 */         stmt.setInt(pos++, item.getParentId());
/*      */       }
/* 1123 */       stmt.setInt(pos++, (int)(item.getDate() / 1000L));
/* 1124 */       stmt.setLong(pos++, item.getSize());
/* 1125 */       stmt.setLong(pos++, item.getInternalFlagBitmask());
/* 1126 */       stmt.setString(pos++, item.getDigest());
/* 1127 */       stmt.setString(pos++, item.getSortSender());
/* 1128 */       stmt.setString(pos++, item.getSortRecipients());
/* 1129 */       stmt.setString(pos++, item.getSortSubject());
/* 1130 */       stmt.setString(pos++, name);
/* 1131 */       stmt.setString(pos++, checkMetadataLength(metadata.toString()));
/* 1132 */       stmt.setInt(pos++, this.mailbox.getOperationChangeID());
/* 1133 */       stmt.setInt(pos++, this.mailbox.getOperationTimestamp());
/* 1134 */       stmt.setInt(pos++, item.getSavedSequence());
/* 1135 */       stmt.setString(pos++, item.getLocator());
/* 1136 */       pos = setMailboxId(stmt, this.mailbox, pos);
/* 1137 */       stmt.setInt(pos++, item.getId());
/* 1138 */       stmt.executeUpdate();
/*      */       
/* 1140 */       if (this.mailbox.isItemModified(item, 4)) {
/* 1141 */         DbTag.updateTagReferences(this.mailbox, item.getId(), item.getType(), item.getInternalFlagBitmask(), item.isUnread(), item.getTags());
/*      */       }
/*      */     }
/*      */     catch (SQLException e)
/*      */     {
/* 1146 */       if (Db.errorMatches(e, Db.Error.DUPLICATE_ROW)) {
/* 1147 */         throw MailServiceException.ALREADY_EXISTS(item.getName(), e);
/*      */       }
/* 1149 */       throw ServiceException.FAILURE("Failed to update item mbox=" + this.mailbox.getId() + ",id=" + item.getId(), e);
/*      */     }
/*      */     finally {
/* 1152 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void saveBlobInfo(MailItem item) throws ServiceException {
/* 1157 */     Mailbox mbox = item.getMailbox();
/* 1158 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 1159 */     PreparedStatement stmt = null;
/*      */     try {
/* 1161 */       stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(item) + " SET size = ?, blob_digest = ?, locator = ?" + " WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */       
/*      */ 
/* 1164 */       int pos = 1;
/* 1165 */       stmt.setLong(pos++, item.getSize());
/* 1166 */       stmt.setString(pos++, item.getDigest());
/* 1167 */       stmt.setString(pos++, item.getLocator());
/* 1168 */       pos = setMailboxId(stmt, mbox, pos);
/* 1169 */       stmt.setInt(pos++, item.getId());
/* 1170 */       stmt.executeUpdate();
/*      */     } catch (SQLException e) {
/* 1172 */       throw ServiceException.FAILURE("updating blob info for mailbox " + mbox.getId() + ", item " + item.getId(), e);
/*      */     } finally {
/* 1174 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void openConversation(String hash, MailItem item) throws ServiceException {
/* 1179 */     Mailbox mbox = item.getMailbox();
/* 1180 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 1181 */     PreparedStatement stmt = null;
/*      */     try {
/* 1183 */       String command = Db.supports(Db.Capability.REPLACE_INTO) ? "REPLACE" : "INSERT";
/* 1184 */       String mailbox_id = DebugConfig.disableMailboxGroups ? "" : "mailbox_id, ";
/* 1185 */       stmt = conn.prepareStatement(command + " INTO " + getConversationTableName(item) + "(" + mailbox_id + "hash, conv_id)" + " VALUES (" + (DebugConfig.disableMailboxGroups ? "" : "?, ") + "?, ?)");
/*      */       
/*      */ 
/* 1188 */       int pos = 1;
/* 1189 */       pos = setMailboxId(stmt, mbox, pos);
/* 1190 */       stmt.setString(pos++, hash);
/* 1191 */       stmt.setInt(pos++, item.getId());
/* 1192 */       stmt.executeUpdate();
/*      */     } catch (SQLException e) {
/* 1194 */       if (Db.errorMatches(e, Db.Error.DUPLICATE_ROW)) {
/*      */         try {
/* 1196 */           DbPool.closeStatement(stmt);
/*      */           
/* 1198 */           stmt = conn.prepareStatement("UPDATE " + getConversationTableName(item) + " SET conv_id = ? WHERE " + IN_THIS_MAILBOX_AND + "hash = ?");
/*      */           
/* 1200 */           int pos = 1;
/* 1201 */           stmt.setInt(pos++, item.getId());
/* 1202 */           pos = setMailboxId(stmt, mbox, pos);
/* 1203 */           stmt.setString(pos++, hash);
/* 1204 */           stmt.executeUpdate();
/*      */         } catch (SQLException nested) {
/* 1206 */           throw ServiceException.FAILURE("updating open conversation association for hash " + hash, nested);
/*      */         }
/*      */       } else {
/* 1209 */         throw ServiceException.FAILURE("writing open conversation association for hash " + hash, e);
/*      */       }
/*      */     } finally {
/* 1212 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void closeConversation(String hash, MailItem item) throws ServiceException {
/* 1217 */     Mailbox mbox = item.getMailbox();
/*      */     
/* 1219 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 1220 */     PreparedStatement stmt = null;
/*      */     try {
/* 1222 */       stmt = conn.prepareStatement("DELETE FROM " + getConversationTableName(item) + " WHERE " + IN_THIS_MAILBOX_AND + "hash = ? AND conv_id = ?");
/*      */       
/* 1224 */       int pos = 1;
/* 1225 */       pos = setMailboxId(stmt, mbox, pos);
/* 1226 */       stmt.setString(pos++, hash);
/* 1227 */       stmt.setInt(pos++, item.getId());
/* 1228 */       stmt.executeUpdate();
/*      */     } catch (SQLException e) {
/* 1230 */       throw ServiceException.FAILURE("closing open conversation association for hash " + hash, e);
/*      */     } finally {
/* 1232 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static void closeOldConversations(Mailbox mbox, int beforeDate)
/*      */     throws ServiceException
/*      */   {
/* 1244 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 1245 */     PreparedStatement stmt = null;
/* 1246 */     ZimbraLog.purge.debug("Closing conversations dated before %d.", new Object[] { Integer.valueOf(beforeDate) });
/*      */     try {
/* 1248 */       String mailboxJoin = DebugConfig.disableMailboxGroups ? "" : " AND mi.mailbox_id = open_conversation.mailbox_id";
/* 1249 */       stmt = conn.prepareStatement("DELETE FROM " + getConversationTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + "conv_id IN (" + "  SELECT id FROM " + getMailItemTableName(mbox, "mi") + "  WHERE mi.id = open_conversation.conv_id" + mailboxJoin + "  AND date < ?)");
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 1255 */       int pos = 1;
/* 1256 */       pos = setMailboxId(stmt, mbox, pos);
/* 1257 */       stmt.setInt(pos++, beforeDate);
/* 1258 */       int numRows = stmt.executeUpdate();
/* 1259 */       if (numRows > 0) {
/* 1260 */         ZimbraLog.purge.info("Closed %d conversations dated before %d.", new Object[] { Integer.valueOf(numRows), Integer.valueOf(beforeDate) });
/*      */       }
/*      */     } catch (SQLException e) {
/* 1263 */       throw ServiceException.FAILURE("closing open conversations dated before " + beforeDate, e);
/*      */     } finally {
/* 1265 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void changeOpenTargets(MailItem oldTarget, int newTargetId) throws ServiceException {
/* 1270 */     Mailbox mbox = oldTarget.getMailbox();
/* 1271 */     int oldTargetId = (oldTarget instanceof VirtualConversation) ? ((VirtualConversation)oldTarget).getMessageId() : oldTarget.getId();
/*      */     
/* 1273 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 1274 */     PreparedStatement stmt = null;
/*      */     try {
/* 1276 */       stmt = conn.prepareStatement("UPDATE " + getConversationTableName(oldTarget) + " SET conv_id = ? WHERE " + IN_THIS_MAILBOX_AND + "conv_id = ?");
/*      */       
/* 1278 */       int pos = 1;
/* 1279 */       stmt.setInt(pos++, newTargetId);
/* 1280 */       pos = setMailboxId(stmt, mbox, pos);
/* 1281 */       stmt.setInt(pos++, oldTargetId);
/* 1282 */       stmt.executeUpdate();
/*      */     } catch (SQLException e) {
/* 1284 */       throw ServiceException.FAILURE("switching open conversation association for item " + oldTarget.getId(), e);
/*      */     } finally {
/* 1286 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void saveDate(MailItem item) throws ServiceException {
/* 1291 */     Mailbox mbox = item.getMailbox();
/* 1292 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 1293 */     PreparedStatement stmt = null;
/*      */     try {
/* 1295 */       stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(mbox) + " SET date = ?, mod_metadata = ?, change_date = ? WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */       
/* 1297 */       int pos = 1;
/* 1298 */       stmt.setInt(pos++, (int)(item.getDate() / 1000L));
/* 1299 */       stmt.setInt(pos++, mbox.getOperationChangeID());
/* 1300 */       stmt.setInt(pos++, mbox.getOperationTimestamp());
/* 1301 */       pos = setMailboxId(stmt, mbox, pos);
/* 1302 */       stmt.setInt(pos++, item.getId());
/* 1303 */       stmt.executeUpdate();
/*      */     } catch (SQLException e) {
/* 1305 */       throw ServiceException.FAILURE("setting IMAP UID for item " + item.getId(), e);
/*      */     } finally {
/* 1307 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static int updateLocatorAndDigest(DbPool.DbConnection conn, Mailbox mbox, String tableName, String idColumn, int itemId, int revision, String locator, String digest) throws ServiceException
/*      */   {
/* 1313 */     PreparedStatement stmt = null;
/*      */     try {
/* 1315 */       stmt = conn.prepareStatement("UPDATE " + tableName + " SET locator = ?, blob_digest = ?" + " WHERE " + IN_THIS_MAILBOX_AND + idColumn + " = ? AND mod_content=?");
/*      */       
/*      */ 
/* 1318 */       int pos = 1;
/* 1319 */       stmt.setString(pos++, locator);
/* 1320 */       stmt.setString(pos++, digest);
/* 1321 */       pos = setMailboxId(stmt, mbox, pos);
/* 1322 */       stmt.setInt(pos++, itemId);
/* 1323 */       stmt.setInt(pos++, revision);
/* 1324 */       return stmt.executeUpdate();
/*      */     } catch (SQLException e) {
/* 1326 */       throw ServiceException.FAILURE("updating locator and digest " + itemId + "-" + revision, e);
/*      */     } finally {
/* 1328 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void saveImapUid(MailItem item) throws ServiceException {
/* 1333 */     Mailbox mbox = item.getMailbox();
/* 1334 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 1335 */     PreparedStatement stmt = null;
/*      */     try {
/* 1337 */       stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(mbox) + " SET imap_id = ?, mod_metadata = ?, change_date = ?" + " WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */       
/*      */ 
/* 1340 */       int pos = 1;
/* 1341 */       stmt.setInt(pos++, item.getImapUid());
/* 1342 */       stmt.setInt(pos++, mbox.getOperationChangeID());
/* 1343 */       stmt.setInt(pos++, mbox.getOperationTimestamp());
/* 1344 */       pos = setMailboxId(stmt, mbox, pos);
/* 1345 */       stmt.setInt(pos++, item.getId());
/* 1346 */       stmt.executeUpdate();
/*      */     } catch (SQLException e) {
/* 1348 */       throw ServiceException.FAILURE("setting IMAP UID for item " + item.getId(), e);
/*      */     } finally {
/* 1350 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void alterUnread(Mailbox mbox, List<Integer> itemIDs, boolean unread) throws ServiceException
/*      */   {
/* 1356 */     if ((itemIDs == null) || (itemIDs.isEmpty())) {
/* 1357 */       return;
/*      */     }
/*      */     
/* 1360 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 1361 */     PreparedStatement stmt = null;
/*      */     try {
/* 1363 */       for (int i = 0; i < itemIDs.size(); i += Db.getINClauseBatchSize()) {
/* 1364 */         int count = Math.min(Db.getINClauseBatchSize(), itemIDs.size() - i);
/* 1365 */         stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(mbox) + " SET unread = ?, mod_metadata = ?, change_date = ?" + " WHERE " + IN_THIS_MAILBOX_AND + "unread = ?" + "  AND " + DbUtil.whereIn("id", count) + "  AND " + typeIn(MailItem.Type.MESSAGE));
/*      */         
/*      */ 
/*      */ 
/*      */ 
/* 1370 */         int pos = 1;
/* 1371 */         stmt.setInt(pos++, unread ? 1 : 0);
/* 1372 */         stmt.setInt(pos++, mbox.getOperationChangeID());
/* 1373 */         stmt.setInt(pos++, mbox.getOperationTimestamp());
/* 1374 */         pos = setMailboxId(stmt, mbox, pos);
/* 1375 */         stmt.setInt(pos++, unread ? 0 : 1);
/* 1376 */         for (int index = i; index < i + count; index++) {
/* 1377 */           stmt.setInt(pos++, ((Integer)itemIDs.get(index)).intValue());
/*      */         }
/* 1379 */         stmt.executeUpdate();
/* 1380 */         stmt.close();
/* 1381 */         stmt = null;
/*      */         
/* 1383 */         if (unread) {
/* 1384 */           DbTag.addTaggedItemEntries(mbox, Flag.ID_UNREAD, itemIDs.subList(i, i + count));
/*      */         } else {
/* 1386 */           DbTag.removeTaggedItemEntries(mbox, Flag.ID_UNREAD, itemIDs.subList(i, i + count));
/*      */         }
/*      */       }
/*      */     } catch (SQLException e) {
/* 1390 */       throw ServiceException.FAILURE("updating unread state for " + itemIDs.size() + " items: " + getIdListForLogging(itemIDs), e);
/*      */     }
/*      */     finally {
/* 1393 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static List<Integer> markDeletionTargets(Folder folder, Set<Integer> candidates)
/*      */     throws ServiceException
/*      */   {
/* 1407 */     Mailbox mbox = folder.getMailbox();
/* 1408 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 1409 */     PreparedStatement stmt = null;
/* 1410 */     ResultSet rs = null;
/*      */     try { int pos;
/* 1412 */       if (Db.supports(Db.Capability.MULTITABLE_UPDATE)) {
/* 1413 */         stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(folder) + ", " + "(SELECT parent_id pid, COUNT(*) count FROM " + getMailItemTableName(folder) + " WHERE " + IN_THIS_MAILBOX_AND + "folder_id = ? AND parent_id IS NOT NULL GROUP BY parent_id) AS x" + " SET size = size - count, metadata = NULL, mod_metadata = ?, change_date = ?" + " WHERE " + IN_THIS_MAILBOX_AND + "id = pid AND type = " + MailItem.Type.CONVERSATION.toByte());
/*      */         
/*      */ 
/*      */ 
/*      */ 
/* 1418 */         int pos = 1;
/* 1419 */         pos = setMailboxId(stmt, mbox, pos);
/* 1420 */         stmt.setInt(pos++, folder.getId());
/* 1421 */         stmt.setInt(pos++, mbox.getOperationChangeID());
/* 1422 */         stmt.setInt(pos++, mbox.getOperationTimestamp());
/* 1423 */         pos = setMailboxId(stmt, mbox, pos);
/* 1424 */         stmt.executeUpdate();
/* 1425 */         stmt.close();
/*      */       } else {
/* 1427 */         stmt = conn.prepareStatement("SELECT parent_id, COUNT(*) FROM " + getMailItemTableName(folder) + " WHERE " + IN_THIS_MAILBOX_AND + "folder_id = ? AND parent_id IS NOT NULL" + " GROUP BY parent_id");
/*      */         
/*      */ 
/* 1430 */         pos = 1;
/* 1431 */         pos = setMailboxId(stmt, mbox, pos);
/* 1432 */         stmt.setInt(pos++, folder.getId());
/* 1433 */         rs = stmt.executeQuery();
/* 1434 */         Map<Integer, List<Integer>> counts = new HashMap();
/* 1435 */         while (rs.next()) {
/* 1436 */           int convId = rs.getInt(1);int count = rs.getInt(2);
/* 1437 */           List<Integer> targets = (List)counts.get(Integer.valueOf(count));
/* 1438 */           if (targets == null) {
/* 1439 */             counts.put(Integer.valueOf(count), targets = new ArrayList());
/*      */           }
/* 1441 */           targets.add(Integer.valueOf(convId));
/*      */         }
/* 1443 */         rs.close();
/* 1444 */         stmt.close();
/*      */         
/* 1446 */         for (Map.Entry<Integer, List<Integer>> update : counts.entrySet()) {
/* 1447 */           List<Integer> convIDs = (List)update.getValue();
/* 1448 */           for (int i = 0; i < convIDs.size(); i += Db.getINClauseBatchSize()) {
/* 1449 */             int count = Math.min(Db.getINClauseBatchSize(), convIDs.size() - i);
/* 1450 */             stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(folder) + " SET size = size - ?, metadata = NULL, mod_metadata = ?, change_date = ?" + " WHERE " + IN_THIS_MAILBOX_AND + DbUtil.whereIn("id", count) + "  AND type = " + MailItem.Type.CONVERSATION.toByte());
/*      */             
/*      */ 
/*      */ 
/* 1454 */             pos = 1;
/* 1455 */             stmt.setInt(pos++, ((Integer)update.getKey()).intValue());
/* 1456 */             stmt.setInt(pos++, mbox.getOperationChangeID());
/* 1457 */             stmt.setInt(pos++, mbox.getOperationTimestamp());
/* 1458 */             pos = setMailboxId(stmt, mbox, pos);
/* 1459 */             for (int index = i; index < i + count; index++) {
/* 1460 */               stmt.setInt(pos++, ((Integer)convIDs.get(index)).intValue());
/*      */             }
/* 1462 */             stmt.executeUpdate();
/* 1463 */             stmt.close();
/*      */           }
/*      */         }
/*      */       }
/*      */       
/* 1468 */       return getPurgedConversations(mbox, candidates);
/*      */     } catch (SQLException e) {
/* 1470 */       throw ServiceException.FAILURE("marking deletions for conversations crossing folder " + folder.getId(), e);
/*      */     } finally {
/* 1472 */       DbPool.closeResults(rs);
/* 1473 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static List<Integer> markDeletionTargets(Mailbox mbox, List<Integer> ids, Set<Integer> candidates)
/*      */     throws ServiceException
/*      */   {
/* 1488 */     if (ids == null) {
/* 1489 */       return null;
/*      */     }
/*      */     
/* 1492 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 1493 */     PreparedStatement stmt = null;
/* 1494 */     ResultSet rs = null;
/*      */     try {
/* 1496 */       String table = getMailItemTableName(mbox);
/* 1497 */       if (Db.supports(Db.Capability.MULTITABLE_UPDATE)) {
/* 1498 */         for (int i = 0; i < ids.size(); i += Db.getINClauseBatchSize()) {
/* 1499 */           int count = Math.min(Db.getINClauseBatchSize(), ids.size() - i);
/* 1500 */           stmt = conn.prepareStatement("UPDATE " + table + ", " + "(SELECT parent_id pid, COUNT(*) count FROM " + getMailItemTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + DbUtil.whereIn("id", count) + " AND parent_id IS NOT NULL GROUP BY parent_id) AS x" + " SET size = size - count, metadata = NULL, mod_metadata = ?, change_date = ?" + " WHERE " + IN_THIS_MAILBOX_AND + "id = pid AND type = " + MailItem.Type.CONVERSATION.toByte());
/*      */           
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 1506 */           int pos = 1;
/* 1507 */           pos = setMailboxId(stmt, mbox, pos);
/* 1508 */           for (int index = i; index < i + count; index++) {
/* 1509 */             stmt.setInt(pos++, ((Integer)ids.get(index)).intValue());
/*      */           }
/* 1511 */           stmt.setInt(pos++, mbox.getOperationChangeID());
/* 1512 */           stmt.setInt(pos++, mbox.getOperationTimestamp());
/* 1513 */           pos = setMailboxId(stmt, mbox, pos);
/* 1514 */           stmt.executeUpdate();
/* 1515 */           stmt.close();
/*      */         }
/*      */       } else {
/* 1518 */         stmt = conn.prepareStatement("SELECT parent_id, COUNT(*) FROM " + getMailItemTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + DbUtil.whereIn("id", ids.size()) + " AND parent_id IS NOT NULL" + " GROUP BY parent_id");
/*      */         
/*      */ 
/* 1521 */         pos = 1;
/* 1522 */         pos = setMailboxId(stmt, mbox, pos);
/* 1523 */         for (Iterator i$ = ids.iterator(); i$.hasNext();) { int id = ((Integer)i$.next()).intValue();
/* 1524 */           stmt.setInt(pos++, id);
/*      */         }
/* 1526 */         rs = stmt.executeQuery();
/* 1527 */         Map<Integer, List<Integer>> counts = new HashMap();
/* 1528 */         while (rs.next()) {
/* 1529 */           int convId = rs.getInt(1);int count = rs.getInt(2);
/* 1530 */           List<Integer> targets = (List)counts.get(Integer.valueOf(count));
/* 1531 */           if (targets == null) {
/* 1532 */             counts.put(Integer.valueOf(count), targets = new ArrayList());
/*      */           }
/* 1534 */           targets.add(Integer.valueOf(convId));
/*      */         }
/* 1536 */         rs.close();
/* 1537 */         stmt.close();
/*      */         
/* 1539 */         for (Map.Entry<Integer, List<Integer>> update : counts.entrySet()) {
/* 1540 */           stmt = conn.prepareStatement("UPDATE " + getMailItemTableName(mbox) + " SET size = size - ?, metadata = NULL, mod_metadata = ?, change_date = ?" + " WHERE " + IN_THIS_MAILBOX_AND + DbUtil.whereIn("id", ((List)update.getValue()).size()) + " AND type = " + MailItem.Type.CONVERSATION.toByte());
/*      */           
/*      */ 
/*      */ 
/* 1544 */           pos = 1;
/* 1545 */           stmt.setInt(pos++, ((Integer)update.getKey()).intValue());
/* 1546 */           stmt.setInt(pos++, mbox.getOperationChangeID());
/* 1547 */           stmt.setInt(pos++, mbox.getOperationTimestamp());
/* 1548 */           pos = setMailboxId(stmt, mbox, pos);
/* 1549 */           for (Iterator i$ = ((List)update.getValue()).iterator(); i$.hasNext();) { int convId = ((Integer)i$.next()).intValue();
/* 1550 */             stmt.setInt(pos++, convId);
/*      */           }
/* 1552 */           stmt.executeUpdate();
/* 1553 */           stmt.close();
/*      */         }
/*      */       }
/*      */     } catch (SQLException e) { int pos;
/* 1557 */       throw ServiceException.FAILURE("marking deletions for conversations touching " + ids.size() + " items: " + getIdListForLogging(ids), e);
/*      */     }
/*      */     finally {
/* 1560 */       DbPool.closeResults(rs);
/* 1561 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */     
/* 1564 */     return getPurgedConversations(mbox, candidates);
/*      */   }
/*      */   
/*      */   private static List<Integer> getPurgedConversations(Mailbox mbox, Set<Integer> candidates) throws ServiceException {
/* 1568 */     if ((candidates == null) || (candidates.isEmpty())) {
/* 1569 */       return null;
/*      */     }
/* 1571 */     List<Integer> purgedConvs = new ArrayList();
/* 1572 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 1573 */     PreparedStatement stmt = null;
/* 1574 */     ResultSet rs = null;
/*      */     try
/*      */     {
/* 1577 */       Iterator<Integer> it = candidates.iterator();
/* 1578 */       for (int i = 0; i < candidates.size(); i += Db.getINClauseBatchSize()) {
/* 1579 */         int count = Math.min(Db.getINClauseBatchSize(), candidates.size() - i);
/* 1580 */         stmt = conn.prepareStatement("SELECT id FROM " + getMailItemTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + DbUtil.whereIn("id", count) + " AND size <= 0");
/*      */         
/* 1582 */         int pos = 1;
/* 1583 */         pos = setMailboxId(stmt, mbox, pos);
/* 1584 */         for (int index = i; index < i + count; index++) {
/* 1585 */           stmt.setInt(pos++, ((Integer)it.next()).intValue());
/*      */         }
/* 1587 */         rs = stmt.executeQuery();
/*      */         
/* 1589 */         while (rs.next()) {
/* 1590 */           purgedConvs.add(Integer.valueOf(rs.getInt(1)));
/*      */         }
/* 1592 */         rs.close();rs = null;
/* 1593 */         stmt.close();stmt = null;
/*      */       }
/*      */       
/* 1596 */       return purgedConvs;
/*      */     } catch (SQLException e) {
/* 1598 */       throw ServiceException.FAILURE("getting list of purged conversations", e);
/*      */     } finally {
/* 1600 */       DbPool.closeResults(rs);
/* 1601 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static void delete(Mailbox mbox, MailItem item, MailItem.PendingDelete info, boolean fromDumpster)
/*      */     throws ServiceException
/*      */   {
/* 1613 */     boolean unsetDeletedFlag = false;
/* 1614 */     if ((item instanceof Tag)) {
/* 1615 */       return;
/*      */     }
/* 1617 */     List<Integer> allIds = info.itemIds.getAllIds();
/* 1618 */     if (item != null) {
/* 1619 */       unsetDeletedFlag = item.getUnderlyingData().isSet(Flag.FlagInfo.DELETED);
/* 1620 */       allIds.remove(Integer.valueOf(item.getId()));
/*      */     }
/*      */     
/* 1623 */     List<Integer> allComments = info.itemIds.getIds(MailItem.Type.COMMENT);
/* 1624 */     if ((allComments != null) && (allComments.size() != 0)) {
/* 1625 */       delete(mbox, allComments, fromDumpster, unsetDeletedFlag);
/* 1626 */       allIds.removeAll(allComments);
/*      */     }
/*      */     
/* 1629 */     List<Integer> allFolders = info.itemIds.getIds(MailItem.Type.FOLDER);
/* 1630 */     if (allFolders != null) {
/* 1631 */       allIds.removeAll(allFolders);
/*      */     }
/* 1633 */     delete(mbox, allIds, fromDumpster, unsetDeletedFlag);
/*      */     
/* 1635 */     delete(mbox, allFolders, fromDumpster, unsetDeletedFlag);
/* 1636 */     if ((item instanceof VirtualConversation)) {
/* 1637 */       return;
/*      */     }
/* 1639 */     if (((item instanceof Conversation)) && (info.incomplete)) {
/* 1640 */       return;
/*      */     }
/*      */     
/* 1643 */     if (item != null) {
/* 1644 */       delete(mbox, Collections.singletonList(Integer.valueOf(item.getId())), fromDumpster, unsetDeletedFlag);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public static void delete(Mailbox mbox, Collection<Integer> ids, boolean fromDumpster)
/*      */     throws ServiceException
/*      */   {
/* 1653 */     delete(mbox, ids, fromDumpster, false);
/*      */   }
/*      */   
/*      */   public static void delete(Mailbox mbox, Collection<Integer> ids, boolean fromDumpster, boolean unsetDeletedFlag) throws ServiceException
/*      */   {
/* 1658 */     if ((ids == null) || (ids.size() == 0)) {
/* 1659 */       return;
/*      */     }
/* 1661 */     List<Integer> targets = new ArrayList();
/* 1662 */     for (Iterator i$ = ids.iterator(); i$.hasNext();) { int id = ((Integer)i$.next()).intValue();
/* 1663 */       if (id > 0) {
/* 1664 */         targets.add(Integer.valueOf(id));
/*      */       }
/*      */     }
/* 1667 */     if (targets.isEmpty()) {
/* 1668 */       return;
/*      */     }
/*      */     
/* 1671 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 1672 */     for (int offset = 0; offset < targets.size(); offset += Db.getINClauseBatchSize()) {
/* 1673 */       PreparedStatement stmt = null;
/*      */       try {
/* 1675 */         int count = Math.min(Db.getINClauseBatchSize(), targets.size() - offset);
/* 1676 */         if ((!fromDumpster) && (mbox.dumpsterEnabled())) {
/* 1677 */           copyToDumpster(conn, mbox, targets, offset, count, unsetDeletedFlag);
/*      */         }
/* 1679 */         stmt = conn.prepareStatement("DELETE FROM " + getMailItemTableName(mbox, fromDumpster) + " WHERE " + IN_THIS_MAILBOX_AND + DbUtil.whereIn("id", count));
/*      */         
/* 1681 */         int pos = 1;
/* 1682 */         pos = setMailboxId(stmt, mbox, pos);
/* 1683 */         for (int i = offset; i < offset + count; i++) {
/* 1684 */           stmt.setInt(pos++, ((Integer)targets.get(i)).intValue());
/*      */         }
/* 1686 */         stmt.executeUpdate();
/*      */       } catch (SQLException e) {
/* 1688 */         throw ServiceException.FAILURE("deleting " + ids.size() + " item(s): " + getIdListForLogging(ids), e);
/*      */       } finally {
/* 1690 */         DbPool.closeStatement(stmt);
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */ 
/* 1696 */   private static String MAIL_ITEM_DUMPSTER_COPY_SRC_FIELDS = (DebugConfig.disableMailboxGroups ? "" : "mailbox_id, ") + "id, type, parent_id, folder_id, prev_folders, index_id, imap_id, date, size, locator, blob_digest, " + "unread, tag_names, sender, recipients, subject, name, metadata, ?, ?, mod_content, uuid, ";
/*      */   
/*      */ 
/*      */ 
/* 1700 */   private static String MAIL_ITEM_DUMPSTER_COPY_DEST_FIELDS = (DebugConfig.disableMailboxGroups ? "" : "mailbox_id, ") + "id, type, parent_id, folder_id, prev_folders, index_id, imap_id, date, size, locator, blob_digest, " + "unread, tag_names, sender, recipients, subject, name, metadata, mod_metadata, change_date, mod_content, uuid, flags";
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private static void copyToDumpster(DbPool.DbConnection conn, Mailbox mbox, List<Integer> ids, int offset, int count, boolean unsetDeletedFlag)
/*      */     throws SQLException, ServiceException
/*      */   {
/* 1718 */     String miTableName = getMailItemTableName(mbox, false);
/* 1719 */     String dumpsterMiTableName = getMailItemTableName(mbox, true);
/* 1720 */     String ciTableName = getCalendarItemTableName(mbox, false);
/* 1721 */     String dumpsterCiTableName = getCalendarItemTableName(mbox, true);
/* 1722 */     String revTableName = getRevisionTableName(mbox, false);
/* 1723 */     String dumpsterRevTableName = getRevisionTableName(mbox, true);
/*      */     
/*      */ 
/*      */ 
/*      */ 
/* 1728 */     String command = Db.supports(Db.Capability.REPLACE_INTO) ? "REPLACE" : "INSERT";
/* 1729 */     String miWhere = DbUtil.whereIn("id", count) + " AND type IN " + DUMPSTER_TYPES + (!mbox.useDumpsterForSpam() ? " AND folder_id != 4" : "") + " AND folder_id != " + 6;
/*      */     
/*      */ 
/*      */ 
/* 1733 */     PreparedStatement miCopyStmt = null;
/*      */     try {
/* 1735 */       miCopyStmt = conn.prepareStatement(command + " INTO " + dumpsterMiTableName + " (" + MAIL_ITEM_DUMPSTER_COPY_DEST_FIELDS + ")" + " SELECT " + MAIL_ITEM_DUMPSTER_COPY_SRC_FIELDS + (unsetDeletedFlag ? Db.getInstance().bitANDNOT("flags", String.valueOf(Flag.BITMASK_DELETED)) : "flags") + " FROM " + miTableName + " WHERE " + IN_THIS_MAILBOX_AND + miWhere);
/*      */       
/*      */ 
/*      */ 
/* 1739 */       int pos = 1;
/* 1740 */       miCopyStmt.setInt(pos++, mbox.getOperationChangeID());
/* 1741 */       miCopyStmt.setInt(pos++, mbox.getOperationTimestamp());
/* 1742 */       pos = setMailboxId(miCopyStmt, mbox, pos);
/* 1743 */       for (int i = offset; i < offset + count; i++) {
/* 1744 */         miCopyStmt.setInt(pos++, ((Integer)ids.get(i)).intValue());
/*      */       }
/* 1746 */       miCopyStmt.executeUpdate();
/*      */     } finally {
/* 1748 */       DbPool.closeStatement(miCopyStmt);
/*      */     }
/*      */     
/* 1751 */     PreparedStatement ciCopyStmt = null;
/*      */     try {
/* 1753 */       ciCopyStmt = conn.prepareStatement(command + " INTO " + dumpsterCiTableName + " SELECT * FROM " + ciTableName + " WHERE " + IN_THIS_MAILBOX_AND + "item_id IN" + " (SELECT id FROM " + miTableName + " WHERE " + IN_THIS_MAILBOX_AND + miWhere + ")");
/*      */       
/*      */ 
/*      */ 
/* 1757 */       int pos = 1;
/* 1758 */       pos = setMailboxId(ciCopyStmt, mbox, pos);
/* 1759 */       pos = setMailboxId(ciCopyStmt, mbox, pos);
/* 1760 */       for (int i = offset; i < offset + count; i++) {
/* 1761 */         ciCopyStmt.setInt(pos++, ((Integer)ids.get(i)).intValue());
/*      */       }
/* 1763 */       ciCopyStmt.executeUpdate();
/*      */     } finally {
/* 1765 */       DbPool.closeStatement(ciCopyStmt);
/*      */     }
/*      */     
/* 1768 */     PreparedStatement revCopyStmt = null;
/*      */     try {
/* 1770 */       revCopyStmt = conn.prepareStatement(command + " INTO " + dumpsterRevTableName + " SELECT * FROM " + revTableName + " WHERE " + IN_THIS_MAILBOX_AND + "item_id IN" + " (SELECT id FROM " + miTableName + " WHERE " + IN_THIS_MAILBOX_AND + miWhere + ")");
/*      */       
/*      */ 
/*      */ 
/* 1774 */       int pos = 1;
/* 1775 */       pos = setMailboxId(revCopyStmt, mbox, pos);
/* 1776 */       pos = setMailboxId(revCopyStmt, mbox, pos);
/* 1777 */       for (int i = offset; i < offset + count; i++) {
/* 1778 */         revCopyStmt.setInt(pos++, ((Integer)ids.get(i)).intValue());
/*      */       }
/* 1780 */       revCopyStmt.executeUpdate();
/*      */     } finally {
/* 1782 */       DbPool.closeStatement(revCopyStmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void writeTombstones(Mailbox mbox, TypedIdList tombstones) throws ServiceException {
/* 1787 */     if ((tombstones == null) || (tombstones.isEmpty())) {
/* 1788 */       return;
/*      */     }
/*      */     
/* 1791 */     for (Map.Entry<MailItem.Type, List<TypedIdList.ItemInfo>> entry : tombstones) {
/* 1792 */       MailItem.Type type = (MailItem.Type)entry.getKey();
/* 1793 */       switch (type)
/*      */       {
/*      */       case VIRTUAL_CONVERSATION: 
/*      */         break;
/*      */       default: 
/* 1798 */         StringBuilder row = new StringBuilder();
/* 1799 */         for (TypedIdList.ItemInfo stone : (List)entry.getValue())
/*      */         {
/* 1801 */           row.append(row.length() == 0 ? "" : ",").append(stone.getId());
/* 1802 */           if (stone.getUuid() != null)
/*      */           {
/* 1804 */             row.append(':').append(stone.getUuid());
/*      */           }
/*      */           
/*      */ 
/* 1808 */           if (row.length() > 65406) {
/* 1809 */             writeTombstone(mbox, type, row.toString());
/* 1810 */             row.setLength(0);
/*      */           }
/*      */         }
/*      */         
/* 1814 */         writeTombstone(mbox, type, row.toString()); }
/*      */     }
/*      */   }
/*      */   
/*      */   private static void writeTombstone(Mailbox mbox, MailItem.Type type, String row) throws ServiceException {
/* 1819 */     if (Strings.isNullOrEmpty(row)) {
/* 1820 */       return;
/*      */     }
/*      */     
/* 1823 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 1824 */     PreparedStatement stmt = null;
/*      */     try {
/* 1826 */       String mailbox_id = DebugConfig.disableMailboxGroups ? "" : "mailbox_id, ";
/* 1827 */       stmt = conn.prepareStatement("INSERT INTO " + getTombstoneTableName(mbox) + "(" + mailbox_id + "sequence, date, type, ids)" + " VALUES (" + MAILBOX_ID_VALUE + "?, ?, ?, ?)");
/*      */       
/*      */ 
/* 1830 */       int pos = 1;
/* 1831 */       pos = setMailboxId(stmt, mbox, pos);
/* 1832 */       stmt.setInt(pos++, mbox.getOperationChangeID());
/* 1833 */       stmt.setInt(pos++, mbox.getOperationTimestamp());
/* 1834 */       stmt.setByte(pos++, type.toByte());
/* 1835 */       stmt.setString(pos++, row);
/* 1836 */       stmt.executeUpdate();
/*      */     } catch (SQLException e) {
/* 1838 */       throw ServiceException.FAILURE("writing tombstones for " + type + "(s): " + row, e);
/*      */     } finally {
/* 1840 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static List<Integer> readTombstones(Mailbox mbox, DbPool.DbConnection conn, long lastSync, Set<MailItem.Type> types) throws ServiceException
/*      */   {
/* 1846 */     List<Integer> tombstones = new ArrayList();
/* 1847 */     PreparedStatement stmt = null;
/* 1848 */     ResultSet rs = null;
/* 1849 */     StringBuilder typesValue = new StringBuilder();
/* 1850 */     if (types.size() > 1) {
/* 1851 */       typesValue.append("(");
/* 1852 */       int i = 0;
/* 1853 */       for (MailItem.Type type : types) {
/* 1854 */         if (i != 0) {
/* 1855 */           typesValue.append(",");
/*      */         }
/* 1857 */         typesValue.append(type.toByte());
/* 1858 */         i = 1;
/*      */       }
/* 1860 */       typesValue.append(")");
/*      */     }
/*      */     try {
/* 1863 */       stmt = conn.prepareStatement("SELECT ids FROM " + getTombstoneTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + "sequence > ? And type" + (types.size() == 1 ? " = " + ((MailItem.Type)types.iterator().next()).toByte() : new StringBuilder().append(" IN ").append(typesValue).toString()) + " AND ids IS NOT NULL ORDER BY sequence");
/*      */       
/*      */ 
/*      */ 
/* 1867 */       Db.getInstance().enableStreaming(stmt);
/* 1868 */       int pos = 1;
/* 1869 */       pos = setMailboxId(stmt, mbox, pos);
/* 1870 */       stmt.setLong(pos++, lastSync);
/* 1871 */       rs = stmt.executeQuery();
/*      */       String row;
/* 1873 */       while (rs.next()) {
/* 1874 */         row = rs.getString(1);
/* 1875 */         if ((row != null) && (!row.equals("")))
/*      */         {
/*      */ 
/*      */ 
/*      */ 
/* 1880 */           for (String stone : row.split(","))
/*      */             try
/*      */             {
/* 1883 */               int delimiter = stone.indexOf(':');
/* 1884 */               if (delimiter == -1) {
/* 1885 */                 tombstones.add(Integer.valueOf(Integer.parseInt(stone)));
/*      */               } else {
/* 1887 */                 tombstones.add(Integer.valueOf(Integer.parseInt(stone.substring(0, delimiter))));
/*      */               }
/*      */             } catch (NumberFormatException nfe) {
/* 1890 */               ZimbraLog.sync.warn("unparseable TOMBSTONE entry: " + stone);
/*      */             }
/*      */         }
/*      */       }
/* 1894 */       return tombstones;
/*      */     } catch (SQLException e) {
/* 1896 */       throw ServiceException.FAILURE("reading tombstones since change: " + lastSync, e);
/*      */     } finally {
/* 1898 */       DbPool.closeResults(rs);
/* 1899 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static TypedIdList readTombstones(Mailbox mbox, long lastSync) throws ServiceException {
/* 1904 */     TypedIdList tombstones = new TypedIdList();
/*      */     
/* 1906 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 1907 */     PreparedStatement stmt = null;
/* 1908 */     ResultSet rs = null;
/*      */     try {
/* 1910 */       stmt = conn.prepareStatement("SELECT type, ids FROM " + getTombstoneTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + "sequence > ? AND ids IS NOT NULL" + " ORDER BY sequence");
/*      */       
/*      */ 
/* 1913 */       Db.getInstance().enableStreaming(stmt);
/* 1914 */       int pos = 1;
/* 1915 */       pos = setMailboxId(stmt, mbox, pos);
/* 1916 */       stmt.setLong(pos++, lastSync);
/* 1917 */       rs = stmt.executeQuery();
/*      */       MailItem.Type type;
/* 1919 */       while (rs.next()) {
/* 1920 */         type = MailItem.Type.of(rs.getByte(1));
/* 1921 */         String row = rs.getString(2);
/* 1922 */         if ((row != null) && (!row.equals("")))
/*      */         {
/*      */ 
/*      */ 
/*      */ 
/* 1927 */           for (String stone : row.split(","))
/*      */             try
/*      */             {
/* 1930 */               int delimiter = stone.indexOf(':');
/* 1931 */               if (delimiter == -1) {
/* 1932 */                 tombstones.add(type, Integer.valueOf(Integer.parseInt(stone)), null);
/*      */               } else {
/* 1934 */                 tombstones.add(type, Integer.valueOf(Integer.parseInt(stone.substring(0, delimiter))), Strings.emptyToNull(stone.substring(delimiter + 1)));
/*      */               }
/*      */             } catch (NumberFormatException nfe) {
/* 1937 */               ZimbraLog.sync.warn("unparseable TOMBSTONE entry: " + stone);
/*      */             }
/*      */         }
/*      */       }
/* 1941 */       return tombstones;
/*      */     } catch (SQLException e) {
/* 1943 */       throw ServiceException.FAILURE("reading tombstones since change: " + lastSync, e);
/*      */     } finally {
/* 1945 */       DbPool.closeResults(rs);
/* 1946 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static int purgeTombstones(Mailbox mbox, int beforeDate)
/*      */     throws ServiceException
/*      */   {
/* 1959 */     int cutoff = 0;
/*      */     
/* 1961 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 1962 */     PreparedStatement stmt = null;
/* 1963 */     ResultSet rs = null;
/*      */     try {
/* 1965 */       stmt = conn.prepareStatement("SELECT MAX(sequence) FROM " + getTombstoneTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + "date <= ?");
/*      */       
/* 1967 */       int pos = 1;
/* 1968 */       pos = setMailboxId(stmt, mbox, pos);
/* 1969 */       stmt.setLong(pos++, beforeDate);
/* 1970 */       rs = stmt.executeQuery();
/* 1971 */       if (rs.next()) {
/* 1972 */         cutoff = rs.getInt(1);
/*      */       }
/*      */       int numRows;
/* 1975 */       if (cutoff > 0) {
/* 1976 */         stmt = conn.prepareStatement("DELETE FROM " + getTombstoneTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + "sequence <= ?");
/*      */         
/* 1978 */         pos = 1;
/* 1979 */         pos = setMailboxId(stmt, mbox, pos);
/* 1980 */         stmt.setLong(pos++, cutoff);
/* 1981 */         numRows = stmt.executeUpdate();
/* 1982 */         if (numRows > 0) {
/* 1983 */           ZimbraLog.mailbox.info("Purged %d tombstones dated before %d.", new Object[] { Integer.valueOf(numRows), Integer.valueOf(beforeDate) });
/*      */         }
/*      */       }
/*      */       
/* 1987 */       return cutoff;
/*      */     } catch (SQLException e) {
/* 1989 */       throw ServiceException.FAILURE("purging tombstones with date before " + beforeDate, e);
/*      */     } finally {
/* 1991 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static List<Integer> getDumpsterItems(Mailbox mbox, int lastSync, int folderId, int maxTrack) throws ServiceException
/*      */   {
/* 1997 */     List<Integer> result = new ArrayList();
/* 1998 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 1999 */     PreparedStatement stmt = null;
/* 2000 */     ResultSet rs = null;
/*      */     try {
/* 2002 */       stmt = conn.prepareStatement("SELECT id, prev_folders, folder_id, mod_metadata FROM " + getMailItemTableName(mbox, true) + " WHERE " + IN_THIS_MAILBOX_AND + "mod_metadata > ? " + " ORDER BY id");
/*      */       
/*      */ 
/* 2005 */       Db.getInstance().enableStreaming(stmt);
/* 2006 */       int pos = 1;
/* 2007 */       pos = setMailboxId(stmt, mbox, pos);
/* 2008 */       stmt.setLong(pos++, lastSync);
/* 2009 */       rs = stmt.executeQuery();
/*      */       int id;
/* 2011 */       while (rs.next()) {
/* 2012 */         id = rs.getInt(1);
/* 2013 */         String prevFolders = rs.getString(2);
/* 2014 */         int curFolderId = rs.getInt(3);
/* 2015 */         int modseq = rs.getInt(4);
/* 2016 */         if ((lastSync < modseq) && (curFolderId == folderId)) {
/* 2017 */           result.add(Integer.valueOf(id));
/*      */ 
/*      */         }
/* 2020 */         else if (!StringUtil.isNullOrEmpty(prevFolders))
/*      */         {
/*      */ 
/*      */ 
/* 2024 */           String[] mappings = prevFolders.split(";");
/* 2025 */           Map<Integer, Integer> modseq2folders = new HashMap();
/* 2026 */           for (String info : mappings) {
/* 2027 */             String[] meta = info.split(":");
/* 2028 */             modseq2folders.put(Integer.valueOf(Integer.parseInt(meta[0])), Integer.valueOf(Integer.parseInt(meta[1])));
/*      */           }
/* 2030 */           if (modseq2folders.containsValue(Integer.valueOf(folderId)))
/*      */           {
/*      */ 
/* 2033 */             int index = 0;
/* 2034 */             while ((index < mappings.length) && (index < maxTrack)) {
/* 2035 */               String md2id = mappings[(index++)];
/* 2036 */               String[] pair = md2id.split(":");
/* 2037 */               int md = Integer.parseInt(pair[0]);
/* 2038 */               if ((lastSync < md) && 
/* 2039 */                 (folderId == Integer.parseInt(pair[1]))) {
/* 2040 */                 result.add(Integer.valueOf(id));
/* 2041 */                 break;
/*      */               }
/*      */             }
/*      */           }
/*      */         } }
/* 2046 */       return result;
/*      */     } catch (SQLException e) {
/* 2048 */       throw ServiceException.FAILURE("reading mail_item_dumpster since modseq: " + lastSync, e);
/*      */     } finally {
/* 2050 */       DbPool.closeResults(rs);
/* 2051 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/* 2055 */   private static final String FOLDER_TYPES = "(" + MailItem.Type.FOLDER.toByte() + ',' + MailItem.Type.SEARCHFOLDER.toByte() + ',' + MailItem.Type.MOUNTPOINT.toByte() + ')';
/*      */   
/*      */ 
/*      */ 
/*      */ 
/* 2060 */   private static final String MESSAGE_TYPES = "(" + MailItem.Type.MESSAGE.toByte() + ',' + MailItem.Type.CHAT.toByte() + ')';
/*      */   
/*      */ 
/*      */ 
/*      */ 
/* 2065 */   private static final String DOCUMENT_TYPES = "(" + MailItem.Type.DOCUMENT.toByte() + ',' + MailItem.Type.LINK.toByte() + ',' + MailItem.Type.WIKI.toByte() + ')';
/*      */   
/*      */ 
/*      */ 
/*      */ 
/* 2070 */   private static final String CALENDAR_TYPES = "(" + MailItem.Type.APPOINTMENT.toByte() + ',' + MailItem.Type.TASK.toByte() + ')';
/*      */   
/*      */ 
/*      */ 
/* 2074 */   private static final String DUMPSTER_TYPES = "(" + MailItem.Type.MESSAGE.toByte() + ',' + MailItem.Type.CONTACT.toByte() + ',' + MailItem.Type.DOCUMENT.toByte() + ',' + MailItem.Type.LINK.toByte() + ',' + MailItem.Type.APPOINTMENT.toByte() + ',' + MailItem.Type.TASK.toByte() + ',' + MailItem.Type.CHAT.toByte() + ',' + MailItem.Type.COMMENT.toByte() + ')';
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 2084 */   public static final String NON_SEARCHABLE_TYPES = "(" + MailItem.Type.FOLDER.toByte() + ',' + MailItem.Type.SEARCHFOLDER.toByte() + ',' + MailItem.Type.MOUNTPOINT.toByte() + ',' + MailItem.Type.TAG.toByte() + ',' + MailItem.Type.CONVERSATION.toByte() + ')';
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 2091 */   public static final String NON_SYNCABLE_TYPES = "(" + MailItem.Type.FOLDER.toByte() + ',' + MailItem.Type.SEARCHFOLDER.toByte() + ',' + MailItem.Type.MOUNTPOINT.toByte() + ',' + MailItem.Type.TAG.toByte() + ')';
/*      */   static final String LEAF_NODE_FIELDS = "id, size, type, unread, folder_id, parent_id, blob_digest, mod_content, mod_metadata, flags, index_id, locator, tag_names, uuid";
/*      */   private static final int LEAF_CI_ID = 1;
/*      */   private static final int LEAF_CI_SIZE = 2;
/*      */   private static final int LEAF_CI_TYPE = 3;
/*      */   
/*      */   private static String typeIn(MailItem.Type type)
/*      */   {
/* 2099 */     switch (type) {
/* 2100 */     case FOLDER:  return "type IN " + FOLDER_TYPES;
/* 2101 */     case MESSAGE:  return "type IN " + MESSAGE_TYPES;
/* 2102 */     case DOCUMENT:  return "type IN " + DOCUMENT_TYPES; }
/* 2103 */     return "type = " + type.toByte();
/*      */   }
/*      */   
/*      */   public static class FolderTagMap extends HashMap<MailItem.UnderlyingData, DbMailItem.FolderTagCounts>
/*      */   {}
/*      */   
/*      */   public static class FolderTagCounts
/*      */   {
/*      */     public long totalSize;
/*      */     public int deletedCount;
/*      */     public int deletedUnreadCount;
/*      */     
/*      */     public String toString() {
/* 2116 */       return this.totalSize + "/" + this.deletedCount + "/" + this.deletedUnreadCount;
/*      */     }
/*      */   }
/*      */   
/*      */   public static Mailbox.MailboxData getFoldersAndTags(Mailbox mbox, FolderTagMap folderData, FolderTagMap tagData, boolean forceReload) throws ServiceException
/*      */   {
/* 2122 */     boolean reload = forceReload;
/*      */     
/* 2124 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 2125 */     PreparedStatement stmt = null;
/* 2126 */     ResultSet rs = null;
/*      */     try {
/* 2128 */       String table = getMailItemTableName(mbox, "mi");
/*      */       
/*      */ 
/* 2131 */       stmt = conn.prepareStatement("SELECT mi.id, mi.type, mi.parent_id, mi.folder_id, mi.prev_folders, mi.index_id,mi.imap_id, mi.date, mi.size, mi.locator, mi.blob_digest, mi.unread, mi.flags, mi.tag_names, mi.subject,mi.name, mi.metadata, mi.mod_metadata, mi.change_date, mi.mod_content, mi.uuid FROM " + table + " WHERE " + IN_THIS_MAILBOX_AND + "type IN " + FOLDER_TYPES);
/*      */       
/* 2133 */       setMailboxId(stmt, mbox, 1);
/* 2134 */       rs = stmt.executeQuery();
/* 2135 */       while (rs.next()) {
/* 2136 */         MailItem.UnderlyingData data = constructItem(rs);
/* 2137 */         MailItem.Type type = MailItem.Type.of(data.type);
/* 2138 */         if (MailItem.isAcceptableType(MailItem.Type.FOLDER, type)) {
/* 2139 */           folderData.put(data, null);
/* 2140 */         } else if (MailItem.isAcceptableType(MailItem.Type.TAG, type)) {
/* 2141 */           tagData.put(data, null);
/*      */         }
/*      */         
/* 2144 */         rs.getInt(12);
/* 2145 */         reload |= rs.wasNull();
/*      */       }
/* 2147 */       rs.close();
/*      */       
/*      */ 
/* 2150 */       reload |= DbTag.getAllTags(mbox, tagData);
/*      */       
/* 2152 */       for (MailItem.UnderlyingData data : folderData.keySet()) {
/* 2153 */         if (data.parentId != data.folderId)
/*      */         {
/*      */ 
/* 2156 */           stmt.close();
/* 2157 */           stmt = conn.prepareStatement("UPDATE " + table + " SET parent_id = folder_id" + " WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */           
/*      */ 
/* 2160 */           int pos = 1;
/* 2161 */           pos = setMailboxId(stmt, mbox, pos);
/* 2162 */           stmt.setInt(pos++, data.id);
/* 2163 */           stmt.executeUpdate();
/*      */           
/* 2165 */           data.parentId = data.folderId;
/* 2166 */           ZimbraLog.mailbox.info("correcting PARENT_ID column for %s %d", new Object[] { MailItem.Type.of(data.type), Integer.valueOf(data.id) });
/*      */         }
/*      */       }
/*      */       
/* 2170 */       if (!reload) {
/* 2171 */         return null;
/*      */       }
/*      */       
/* 2174 */       Map<Integer, MailItem.UnderlyingData> lookup = new HashMap(folderData.size() + tagData.size());
/*      */       
/*      */ 
/* 2177 */       for (FolderTagMap itemData : new FolderTagMap[] { folderData, tagData }) {
/* 2178 */         for (Map.Entry<MailItem.UnderlyingData, FolderTagCounts> entry : itemData.entrySet()) {
/* 2179 */           MailItem.UnderlyingData data = (MailItem.UnderlyingData)entry.getKey();
/* 2180 */           lookup.put(Integer.valueOf(data.id), data);
/* 2181 */           data.size = (data.unreadCount = 0);
/* 2182 */           entry.setValue(new FolderTagCounts());
/*      */         }
/*      */       }
/*      */       
/* 2186 */       rs.close();
/* 2187 */       stmt.close();
/*      */       
/*      */ 
/* 2190 */       Mailbox.MailboxData mbd = new Mailbox.MailboxData();
/* 2191 */       stmt = conn.prepareStatement("SELECT folder_id, type, flags, COUNT(*), SUM(unread), SUM(size) FROM " + table + " WHERE " + IN_THIS_MAILBOX_AND + "type NOT IN " + NON_SEARCHABLE_TYPES + " GROUP BY folder_id, type, flags");
/*      */       
/*      */ 
/* 2194 */       setMailboxId(stmt, mbox, 1);
/* 2195 */       rs = stmt.executeQuery();
/*      */       
/* 2197 */       while (rs.next()) {
/* 2198 */         int folderId = rs.getInt(1);
/* 2199 */         byte type = rs.getByte(2);
/* 2200 */         boolean deleted = (rs.getInt(3) & Flag.BITMASK_DELETED) != 0;
/* 2201 */         int count = rs.getInt(4);
/* 2202 */         int unread = rs.getInt(5);
/* 2203 */         long size = rs.getLong(6);
/*      */         
/* 2205 */         if (type == MailItem.Type.CONTACT.toByte()) {
/* 2206 */           mbd.contacts += count;
/*      */         }
/* 2208 */         mbd.size += size;
/*      */         
/* 2210 */         MailItem.UnderlyingData data = (MailItem.UnderlyingData)lookup.get(Integer.valueOf(folderId));
/* 2211 */         if (data != null) {
/* 2212 */           data.unreadCount += unread;
/* 2213 */           data.size += count;
/*      */           
/* 2215 */           FolderTagCounts fcounts = (FolderTagCounts)folderData.get(data);
/* 2216 */           fcounts.totalSize += size;
/* 2217 */           if (deleted) {
/* 2218 */             fcounts.deletedCount += count;
/* 2219 */             fcounts.deletedUnreadCount += unread;
/*      */           }
/*      */         } else {
/* 2222 */           ZimbraLog.mailbox.warn("inconsistent DB state: items with no corresponding folder (folder id %d)", new Object[] { Integer.valueOf(folderId) });
/*      */         }
/*      */       }
/*      */       
/*      */ 
/* 2227 */       DbTag.recalculateTagCounts(mbox, lookup);
/*      */       
/* 2229 */       rs.close();
/* 2230 */       stmt.close();
/*      */       
/* 2232 */       stmt = conn.prepareStatement("SELECT mi.folder_id, SUM(rev.size) FROM " + table + ", " + getRevisionTableName(mbox, "rev") + " WHERE mi.id = rev.item_id" + (DebugConfig.disableMailboxGroups ? "" : " AND rev.mailbox_id = ? AND mi.mailbox_id = rev.mailbox_id") + " GROUP BY folder_id");
/*      */       
/*      */ 
/*      */ 
/*      */ 
/* 2237 */       setMailboxId(stmt, mbox, 1);
/* 2238 */       rs = stmt.executeQuery();
/*      */       int folderId;
/* 2240 */       while (rs.next()) {
/* 2241 */         folderId = rs.getInt(1);
/* 2242 */         long size = rs.getLong(2);
/*      */         
/* 2244 */         mbd.size += size;
/*      */         
/* 2246 */         MailItem.UnderlyingData data = (MailItem.UnderlyingData)lookup.get(Integer.valueOf(folderId));
/* 2247 */         if (data != null) {
/* 2248 */           ((FolderTagCounts)folderData.get(data)).totalSize += size;
/*      */         } else {
/* 2250 */           ZimbraLog.mailbox.warn("inconsistent DB state: revisions with no corresponding folder (folder ID " + folderId + ")");
/*      */         }
/*      */       }
/*      */       
/* 2254 */       return mbd;
/*      */     } catch (SQLException e) {
/* 2256 */       throw ServiceException.FAILURE("fetching folder data for mailbox " + mbox.getId(), e);
/*      */     } finally {
/* 2258 */       DbPool.closeResults(rs);
/* 2259 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static List<MailItem.UnderlyingData> getByType(Mailbox mbox, MailItem.Type type, SortBy sort) throws ServiceException {
/* 2264 */     if (Mailbox.isCachedType(type)) {
/* 2265 */       throw ServiceException.INVALID_REQUEST("folders and tags must be retrieved from cache", null);
/*      */     }
/* 2267 */     ArrayList<MailItem.UnderlyingData> result = new ArrayList();
/*      */     
/* 2269 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 2270 */     PreparedStatement stmt = null;
/* 2271 */     ResultSet rs = null;
/*      */     try {
/* 2273 */       stmt = conn.prepareStatement("SELECT mi.id, mi.type, mi.parent_id, mi.folder_id, mi.prev_folders, mi.index_id,mi.imap_id, mi.date, mi.size, mi.locator, mi.blob_digest, mi.unread, mi.flags, mi.tag_names, mi.subject,mi.name, mi.metadata, mi.mod_metadata, mi.change_date, mi.mod_content, mi.uuid FROM " + getMailItemTableName(mbox, " mi") + " WHERE " + IN_THIS_MAILBOX_AND + typeIn(type) + DbSearch.orderBy(sort, false));
/*      */       
/*      */ 
/* 2276 */       if (type == MailItem.Type.MESSAGE) {
/* 2277 */         Db.getInstance().enableStreaming(stmt);
/*      */       }
/* 2279 */       setMailboxId(stmt, mbox, 1);
/* 2280 */       rs = stmt.executeQuery();
/* 2281 */       while (rs.next()) {
/* 2282 */         result.add(constructItem(rs));
/*      */       }
/* 2284 */       rs.close();rs = null;
/* 2285 */       stmt.close();stmt = null;
/*      */       
/* 2287 */       if (type == MailItem.Type.CONVERSATION) {
/* 2288 */         completeConversations(mbox, conn, result);
/*      */       }
/* 2290 */       return result;
/*      */     } catch (SQLException e) {
/* 2292 */       throw ServiceException.FAILURE("fetching items of type " + type, e);
/*      */     } finally {
/* 2294 */       DbPool.closeResults(rs);
/* 2295 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static List<MailItem.UnderlyingData> getByParent(MailItem parent) throws ServiceException {
/* 2300 */     return getByParent(parent, SortBy.DATE_DESC, -1, false);
/*      */   }
/*      */   
/*      */   public static List<MailItem.UnderlyingData> getByParent(MailItem parent, SortBy sort, int limit, boolean fromDumpster) throws ServiceException
/*      */   {
/* 2305 */     Mailbox mbox = parent.getMailbox();
/*      */     
/* 2307 */     List<MailItem.UnderlyingData> result = new ArrayList();
/*      */     
/* 2309 */     StringBuilder sql = new StringBuilder("SELECT ").append("mi.id, mi.type, mi.parent_id, mi.folder_id, mi.prev_folders, mi.index_id,mi.imap_id, mi.date, mi.size, mi.locator, mi.blob_digest, mi.unread, mi.flags, mi.tag_names, mi.subject,mi.name, mi.metadata, mi.mod_metadata, mi.change_date, mi.mod_content, mi.uuid").append(" FROM ").append(getMailItemTableName(parent.getMailbox(), " mi", fromDumpster)).append(" WHERE ").append(IN_THIS_MAILBOX_AND).append("parent_id = ? ").append(DbSearch.orderBy(sort, false));
/*      */     
/*      */ 
/*      */ 
/* 2313 */     if (limit > 0) {
/* 2314 */       sql.append(" LIMIT ?");
/*      */     }
/*      */     
/* 2317 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 2318 */     PreparedStatement stmt = null;
/* 2319 */     ResultSet rs = null;
/*      */     try {
/* 2321 */       stmt = conn.prepareStatement(sql.toString());
/* 2322 */       if (parent.getSize() > 10000L) {
/* 2323 */         Db.getInstance().enableStreaming(stmt);
/*      */       }
/* 2325 */       int pos = 1;
/* 2326 */       pos = setMailboxId(stmt, mbox, pos);
/* 2327 */       stmt.setInt(pos++, parent.getId());
/* 2328 */       if (limit > 0) {
/* 2329 */         stmt.setInt(pos++, limit);
/*      */       }
/* 2331 */       rs = stmt.executeQuery();
/*      */       MailItem.UnderlyingData data;
/* 2333 */       while (rs.next()) {
/* 2334 */         data = constructItem(rs, fromDumpster);
/* 2335 */         if (Mailbox.isCachedType(MailItem.Type.of(data.type))) {
/* 2336 */           throw ServiceException.INVALID_REQUEST("folders and tags must be retrieved from cache", null);
/*      */         }
/* 2338 */         result.add(data);
/*      */       }
/* 2340 */       return result;
/*      */     } catch (SQLException e) {
/* 2342 */       throw ServiceException.FAILURE("fetching children of item " + parent.getId(), e);
/*      */     } finally {
/* 2344 */       DbPool.closeResults(rs);
/* 2345 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static List<MailItem.UnderlyingData> getUnreadMessages(MailItem relativeTo) throws ServiceException {
/* 2350 */     if ((relativeTo instanceof Tag)) {
/* 2351 */       return DbTag.getUnreadMessages((Tag)relativeTo);
/*      */     }
/*      */     
/* 2354 */     Mailbox mbox = relativeTo.getMailbox();
/* 2355 */     ArrayList<MailItem.UnderlyingData> result = new ArrayList();
/*      */     
/* 2357 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 2358 */     PreparedStatement stmt = null;
/* 2359 */     ResultSet rs = null;
/*      */     try { String relation;
/*      */       String relation;
/* 2362 */       if ((relativeTo instanceof VirtualConversation)) {
/* 2363 */         relation = "id = ?"; } else { String relation;
/* 2364 */         if ((relativeTo instanceof Conversation)) {
/* 2365 */           relation = "parent_id = ?"; } else { String relation;
/* 2366 */           if ((relativeTo instanceof Folder)) {
/* 2367 */             relation = "folder_id = ?";
/*      */           } else
/* 2369 */             relation = "id = ?";
/*      */         }
/*      */       }
/* 2372 */       stmt = conn.prepareStatement("SELECT mi.id, mi.type, mi.parent_id, mi.folder_id, mi.prev_folders, mi.index_id,mi.imap_id, mi.date, mi.size, mi.locator, mi.blob_digest, mi.unread, mi.flags, mi.tag_names, mi.subject,mi.name, mi.metadata, mi.mod_metadata, mi.change_date, mi.mod_content, mi.uuid FROM " + getMailItemTableName(relativeTo.getMailbox(), " mi") + " WHERE " + IN_THIS_MAILBOX_AND + "unread > 0 AND " + relation + " AND type NOT IN " + NON_SEARCHABLE_TYPES);
/*      */       
/*      */ 
/* 2375 */       if (relativeTo.getUnreadCount() > 10000) {
/* 2376 */         Db.getInstance().enableStreaming(stmt);
/*      */       }
/* 2378 */       int pos = 1;
/* 2379 */       pos = setMailboxId(stmt, mbox, pos);
/* 2380 */       if ((relativeTo instanceof VirtualConversation)) {
/* 2381 */         stmt.setInt(pos++, ((VirtualConversation)relativeTo).getMessageId());
/*      */       } else {
/* 2383 */         stmt.setInt(pos++, relativeTo.getId());
/*      */       }
/* 2385 */       rs = stmt.executeQuery();
/*      */       MailItem.UnderlyingData data;
/* 2387 */       while (rs.next()) {
/* 2388 */         data = constructItem(rs);
/* 2389 */         if (Mailbox.isCachedType(MailItem.Type.of(data.type))) {
/* 2390 */           throw ServiceException.INVALID_REQUEST("folders and tags must be retrieved from cache", null);
/*      */         }
/* 2392 */         result.add(data);
/*      */       }
/* 2394 */       return result;
/*      */     } catch (SQLException e) {
/* 2396 */       throw ServiceException.FAILURE("fetching unread messages for item " + relativeTo.getId(), e);
/*      */     } finally {
/* 2398 */       DbPool.closeResults(rs);
/* 2399 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static List<MailItem.UnderlyingData> getByFolder(Folder folder, MailItem.Type type, SortBy sort) throws ServiceException
/*      */   {
/* 2405 */     if (Mailbox.isCachedType(type)) {
/* 2406 */       throw ServiceException.INVALID_REQUEST("folders and tags must be retrieved from cache", null);
/*      */     }
/* 2408 */     Mailbox mbox = folder.getMailbox();
/*      */     
/* 2410 */     List<MailItem.UnderlyingData> result = new ArrayList();
/*      */     
/* 2412 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 2413 */     PreparedStatement stmt = null;
/* 2414 */     ResultSet rs = null;
/*      */     try {
/* 2416 */       stmt = conn.prepareStatement("SELECT mi.id, mi.type, mi.parent_id, mi.folder_id, mi.prev_folders, mi.index_id,mi.imap_id, mi.date, mi.size, mi.locator, mi.blob_digest, mi.unread, mi.flags, mi.tag_names, mi.subject,mi.name, mi.metadata, mi.mod_metadata, mi.change_date, mi.mod_content, mi.uuid FROM " + getMailItemTableName(folder.getMailbox(), " mi") + " WHERE " + IN_THIS_MAILBOX_AND + "folder_id = ? AND " + typeIn(type) + DbSearch.orderBy(sort, false));
/*      */       
/*      */ 
/*      */ 
/* 2420 */       if ((folder.getSize() > 10000L) && (type == MailItem.Type.MESSAGE)) {
/* 2421 */         Db.getInstance().enableStreaming(stmt);
/*      */       }
/* 2423 */       int pos = 1;
/* 2424 */       pos = setMailboxId(stmt, mbox, pos);
/* 2425 */       stmt.setInt(pos++, folder.getId());
/* 2426 */       rs = stmt.executeQuery();
/*      */       
/* 2428 */       while (rs.next()) {
/* 2429 */         result.add(constructItem(rs));
/*      */       }
/* 2431 */       return result;
/*      */     } catch (SQLException e) {
/* 2433 */       throw ServiceException.FAILURE("fetching items in folder " + folder.getId(), e);
/*      */     } finally {
/* 2435 */       DbPool.closeResults(rs);
/* 2436 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static MailItem.UnderlyingData getById(Mailbox mbox, int id, MailItem.Type type, boolean fromDumpster) throws ServiceException
/*      */   {
/* 2442 */     return getBy(LookupBy.id, mbox, Integer.toString(id), type, fromDumpster);
/*      */   }
/*      */   
/*      */   public static MailItem.UnderlyingData getByUuid(Mailbox mbox, String uuid, MailItem.Type type, boolean fromDumpster) throws ServiceException
/*      */   {
/* 2447 */     return getBy(LookupBy.uuid, mbox, uuid, type, fromDumpster);
/*      */   }
/*      */   
/*      */   private static enum LookupBy {
/* 2451 */     id,  uuid;
/*      */     
/*      */     private LookupBy() {}
/*      */   }
/*      */   
/* 2456 */   private static MailItem.UnderlyingData getBy(LookupBy by, Mailbox mbox, String key, MailItem.Type type, boolean fromDumpster) throws ServiceException { if (Mailbox.isCachedType(type)) {
/* 2457 */       throw ServiceException.INVALID_REQUEST("folders and tags must be retrieved from cache", null);
/*      */     }
/*      */     
/* 2460 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 2461 */     PreparedStatement stmt = null;
/* 2462 */     ResultSet rs = null;
/*      */     try {
/* 2464 */       String keyColumn = LookupBy.uuid.equals(by) ? "uuid" : "id";
/* 2465 */       stmt = conn.prepareStatement("SELECT mi.id, mi.type, mi.parent_id, mi.folder_id, mi.prev_folders, mi.index_id,mi.imap_id, mi.date, mi.size, mi.locator, mi.blob_digest, mi.unread, mi.flags, mi.tag_names, mi.subject,mi.name, mi.metadata, mi.mod_metadata, mi.change_date, mi.mod_content, mi.uuid FROM " + getMailItemTableName(mbox, "mi", fromDumpster) + " WHERE " + IN_THIS_MAILBOX_AND + keyColumn + " = ?");
/*      */       
/*      */ 
/* 2468 */       int pos = 1;
/* 2469 */       pos = setMailboxId(stmt, mbox, pos);
/* 2470 */       stmt.setString(pos++, key);
/* 2471 */       rs = stmt.executeQuery();
/*      */       
/* 2473 */       if (!rs.next()) {
/* 2474 */         if (LookupBy.uuid.equals(by)) {
/* 2475 */           throw MailItem.noSuchItemUuid(key, type);
/*      */         }
/* 2477 */         int id = Integer.parseInt(key);
/* 2478 */         throw MailItem.noSuchItem(id, type);
/*      */       }
/*      */       
/* 2481 */       MailItem.UnderlyingData data = constructItem(rs, fromDumpster);
/* 2482 */       int id; if (!MailItem.isAcceptableType(type, MailItem.Type.of(data.type))) {
/* 2483 */         if (LookupBy.uuid.equals(by)) {
/* 2484 */           throw MailItem.noSuchItemUuid(key, type);
/*      */         }
/* 2486 */         id = Integer.parseInt(key);
/* 2487 */         throw MailItem.noSuchItem(id, type);
/*      */       }
/*      */       
/* 2490 */       if ((!fromDumpster) && (data.type == MailItem.Type.CONVERSATION.toByte())) {
/* 2491 */         completeConversation(mbox, conn, data);
/*      */       }
/* 2493 */       return data;
/*      */     } catch (SQLException e) {
/* 2495 */       if (!fromDumpster) {
/* 2496 */         throw ServiceException.FAILURE("fetching item " + key, e);
/*      */       }
/* 2498 */       throw ServiceException.FAILURE("fetching item " + key + " from dumpster", e);
/*      */     }
/*      */     finally {
/* 2501 */       DbPool.closeResults(rs);
/* 2502 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static MailItem.UnderlyingData getByImapId(Mailbox mbox, int imapId, int folderId) throws ServiceException {
/* 2507 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 2508 */     PreparedStatement stmt = null;
/* 2509 */     ResultSet rs = null;
/*      */     try {
/* 2511 */       stmt = conn.prepareStatement("SELECT mi.id, mi.type, mi.parent_id, mi.folder_id, mi.prev_folders, mi.index_id,mi.imap_id, mi.date, mi.size, mi.locator, mi.blob_digest, mi.unread, mi.flags, mi.tag_names, mi.subject,mi.name, mi.metadata, mi.mod_metadata, mi.change_date, mi.mod_content, mi.uuid FROM " + getMailItemTableName(mbox, "mi") + " WHERE " + IN_THIS_MAILBOX_AND + "folder_id = ? AND imap_id = ?");
/*      */       
/*      */ 
/* 2514 */       int pos = 1;
/* 2515 */       pos = setMailboxId(stmt, mbox, pos);
/* 2516 */       stmt.setInt(pos++, folderId);
/* 2517 */       stmt.setInt(pos++, imapId);
/* 2518 */       rs = stmt.executeQuery();
/*      */       
/* 2520 */       if (!rs.next()) {
/* 2521 */         throw MailServiceException.NO_SUCH_ITEM(imapId);
/*      */       }
/* 2523 */       MailItem.UnderlyingData data = constructItem(rs);
/* 2524 */       if (data.type == MailItem.Type.CONVERSATION.toByte()) {
/* 2525 */         throw MailServiceException.NO_SUCH_ITEM(imapId);
/*      */       }
/* 2527 */       return data;
/*      */     } catch (SQLException e) {
/* 2529 */       throw ServiceException.FAILURE("fetching item " + imapId, e);
/*      */     } finally {
/* 2531 */       DbPool.closeResults(rs);
/* 2532 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static List<MailItem.UnderlyingData> getById(Mailbox mbox, Collection<Integer> ids, MailItem.Type type) throws ServiceException
/*      */   {
/* 2538 */     if (Mailbox.isCachedType(type)) {
/* 2539 */       throw ServiceException.INVALID_REQUEST("folders and tags must be retrieved from cache", null);
/*      */     }
/*      */     
/* 2542 */     List<MailItem.UnderlyingData> result = new ArrayList();
/* 2543 */     if (ids.isEmpty()) {
/* 2544 */       return result;
/*      */     }
/* 2546 */     List<MailItem.UnderlyingData> conversations = new ArrayList();
/*      */     
/* 2548 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 2549 */     PreparedStatement stmt = null;
/* 2550 */     ResultSet rs = null;
/* 2551 */     Iterator<Integer> it = ids.iterator();
/* 2552 */     for (int i = 0; i < ids.size(); i += Db.getINClauseBatchSize()) {
/*      */       try {
/* 2554 */         int count = Math.min(Db.getINClauseBatchSize(), ids.size() - i);
/* 2555 */         stmt = conn.prepareStatement("SELECT mi.id, mi.type, mi.parent_id, mi.folder_id, mi.prev_folders, mi.index_id,mi.imap_id, mi.date, mi.size, mi.locator, mi.blob_digest, mi.unread, mi.flags, mi.tag_names, mi.subject,mi.name, mi.metadata, mi.mod_metadata, mi.change_date, mi.mod_content, mi.uuid FROM " + getMailItemTableName(mbox, "mi") + " WHERE " + IN_THIS_MAILBOX_AND + DbUtil.whereIn("id", count));
/*      */         
/*      */ 
/* 2558 */         int pos = 1;
/* 2559 */         pos = setMailboxId(stmt, mbox, pos);
/* 2560 */         for (int index = i; index < i + count; index++) {
/* 2561 */           stmt.setInt(pos++, ((Integer)it.next()).intValue());
/*      */         }
/*      */         
/* 2564 */         rs = stmt.executeQuery();
/* 2565 */         while (rs.next()) {
/* 2566 */           MailItem.UnderlyingData data = constructItem(rs);
/* 2567 */           MailItem.Type resultType = MailItem.Type.of(data.type);
/* 2568 */           if (!MailItem.isAcceptableType(type, resultType))
/* 2569 */             throw MailItem.noSuchItem(data.id, type);
/* 2570 */           if (Mailbox.isCachedType(resultType)) {
/* 2571 */             throw ServiceException.INVALID_REQUEST("folders and tags must be retrieved from cache", null);
/*      */           }
/* 2573 */           if (resultType == MailItem.Type.CONVERSATION) {
/* 2574 */             conversations.add(data);
/*      */           }
/* 2576 */           result.add(data);
/*      */         }
/*      */       } catch (SQLException e) {
/* 2579 */         throw ServiceException.FAILURE("fetching " + ids.size() + " items: " + getIdListForLogging(ids), e);
/*      */       } finally {
/* 2581 */         DbPool.closeResults(rs);
/* 2582 */         DbPool.closeStatement(stmt);
/*      */       }
/*      */     }
/*      */     
/* 2586 */     if (!conversations.isEmpty()) {
/* 2587 */       completeConversations(mbox, conn, conversations);
/*      */     }
/* 2589 */     return result;
/*      */   }
/*      */   
/*      */   public static MailItem.UnderlyingData getByName(Mailbox mbox, int folderId, String name, MailItem.Type type) throws ServiceException
/*      */   {
/* 2594 */     if (Mailbox.isCachedType(type)) {
/* 2595 */       throw ServiceException.INVALID_REQUEST("folders and tags must be retrieved from cache", null);
/*      */     }
/*      */     
/* 2598 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 2599 */     PreparedStatement stmt = null;
/* 2600 */     ResultSet rs = null;
/*      */     try {
/* 2602 */       stmt = conn.prepareStatement("SELECT mi.id, mi.type, mi.parent_id, mi.folder_id, mi.prev_folders, mi.index_id,mi.imap_id, mi.date, mi.size, mi.locator, mi.blob_digest, mi.unread, mi.flags, mi.tag_names, mi.subject,mi.name, mi.metadata, mi.mod_metadata, mi.change_date, mi.mod_content, mi.uuid FROM " + getMailItemTableName(mbox, "mi") + " WHERE " + IN_THIS_MAILBOX_AND + "folder_id = ? AND " + typeIn(type) + " AND " + Db.equalsSTRING("name"));
/*      */       
/*      */ 
/*      */ 
/* 2606 */       int pos = 1;
/* 2607 */       pos = setMailboxId(stmt, mbox, pos);
/* 2608 */       stmt.setInt(pos++, folderId);
/* 2609 */       stmt.setString(pos++, name);
/* 2610 */       rs = stmt.executeQuery();
/*      */       
/* 2612 */       if (!rs.next()) {
/* 2613 */         throw MailItem.noSuchItem(-1, type);
/*      */       }
/* 2615 */       MailItem.UnderlyingData data = constructItem(rs);
/* 2616 */       MailItem.Type resultType = MailItem.Type.of(data.type);
/* 2617 */       if (!MailItem.isAcceptableType(type, resultType)) {
/* 2618 */         throw MailItem.noSuchItem(data.id, type);
/*      */       }
/* 2620 */       if (resultType == MailItem.Type.CONVERSATION) {
/* 2621 */         completeConversation(mbox, conn, data);
/*      */       }
/* 2623 */       return data;
/*      */     } catch (SQLException e) {
/* 2625 */       throw ServiceException.FAILURE("fetching item by name ('" + name + "' in folder " + folderId + ")", e);
/*      */     } finally {
/* 2627 */       DbPool.closeResults(rs);
/* 2628 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static MailItem.UnderlyingData getByHash(Mailbox mbox, String hash) throws ServiceException {
/* 2633 */     return (MailItem.UnderlyingData)ListUtil.getFirstElement(getByHashes(mbox, Arrays.asList(new String[] { hash })));
/*      */   }
/*      */   
/*      */   public static List<MailItem.UnderlyingData> getByHashes(Mailbox mbox, List<String> hashes) throws ServiceException {
/* 2637 */     if (ListUtil.isEmpty(hashes)) {
/* 2638 */       return null;
/*      */     }
/*      */     
/* 2641 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 2642 */     PreparedStatement stmt = null;
/* 2643 */     ResultSet rs = null;
/*      */     try {
/* 2645 */       stmt = conn.prepareStatement("SELECT mi.id, mi.type, mi.parent_id, mi.folder_id, mi.prev_folders, mi.index_id,mi.imap_id, mi.date, mi.size, mi.locator, mi.blob_digest, mi.unread, mi.flags, mi.tag_names, mi.subject,mi.name, mi.metadata, mi.mod_metadata, mi.change_date, mi.mod_content, mi.uuid FROM " + getMailItemTableName(mbox, "mi") + ", " + getConversationTableName(mbox, "oc") + " WHERE mi.id = oc.conv_id AND " + DbUtil.whereIn("oc.hash", hashes.size()) + (DebugConfig.disableMailboxGroups ? "" : " AND oc.mailbox_id = ? AND mi.mailbox_id = oc.mailbox_id"));
/*      */       
/*      */ 
/*      */ 
/* 2649 */       int pos = 1;
/* 2650 */       for (String hash : hashes) {
/* 2651 */         stmt.setString(pos++, hash);
/*      */       }
/* 2653 */       pos = setMailboxId(stmt, mbox, pos);
/* 2654 */       rs = stmt.executeQuery();
/*      */       
/* 2656 */       List<MailItem.UnderlyingData> dlist = new ArrayList(3);
/* 2657 */       Set<Integer> convIds = Sets.newHashSetWithExpectedSize(3);
/* 2658 */       int id; while (rs.next()) {
/* 2659 */         id = rs.getInt(1);
/* 2660 */         if (!convIds.contains(Integer.valueOf(id)))
/*      */         {
/*      */ 
/*      */ 
/* 2664 */           MailItem.UnderlyingData data = constructItem(rs);
/* 2665 */           if (data.type == MailItem.Type.CONVERSATION.toByte()) {
/* 2666 */             completeConversation(mbox, conn, data);
/*      */           }
/* 2668 */           dlist.add(data);
/* 2669 */           convIds.add(Integer.valueOf(data.id));
/*      */         } }
/* 2671 */       return dlist.isEmpty() ? null : dlist;
/*      */     } catch (SQLException e) {
/* 2673 */       throw ServiceException.FAILURE("fetching conversation for hash " + hashes, e);
/*      */     } finally {
/* 2675 */       DbPool.closeResults(rs);
/* 2676 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static Pair<List<Integer>, TypedIdList> getModifiedItems(Mailbox mbox, MailItem.Type type, long lastSync, int sinceDate, Set<Integer> visible)
/*      */     throws ServiceException
/*      */   {
/* 2683 */     if (Mailbox.isCachedType(type)) {
/* 2684 */       throw ServiceException.INVALID_REQUEST("folders and tags must be retrieved from cache", null);
/*      */     }
/* 2686 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 2687 */     PreparedStatement stmt = null;
/*      */     try {
/* 2689 */       String typeConstraint = type == MailItem.Type.UNKNOWN ? "type NOT IN " + NON_SYNCABLE_TYPES : typeIn(type);
/* 2690 */       String dateConstraint = sinceDate > 0 ? "date > ? AND " : "";
/* 2691 */       stmt = conn.prepareStatement("SELECT id, type, folder_id, uuid FROM " + getMailItemTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + "mod_metadata > ? AND " + dateConstraint + typeConstraint + " ORDER BY mod_metadata, id");
/*      */       
/*      */ 
/*      */ 
/* 2695 */       if (type == MailItem.Type.MESSAGE) {
/* 2696 */         Db.getInstance().enableStreaming(stmt);
/*      */       }
/* 2698 */       int pos = 1;
/* 2699 */       pos = setMailboxId(stmt, mbox, pos);
/* 2700 */       stmt.setLong(pos++, lastSync);
/* 2701 */       if (sinceDate > 0) {
/* 2702 */         stmt.setInt(pos++, sinceDate);
/*      */       }
/*      */       
/* 2705 */       return populateWithResultSetData(visible, stmt);
/*      */     } catch (SQLException e) {
/* 2707 */       throw ServiceException.FAILURE("getting items modified since " + lastSync, e);
/*      */     } finally {
/* 2709 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static Pair<List<Integer>, TypedIdList> getItemsChangedSinceDate(Mailbox mbox, MailItem.Type type, int changeDate, Set<Integer> visible)
/*      */     throws ServiceException
/*      */   {
/* 2716 */     if (Mailbox.isCachedType(type)) {
/* 2717 */       throw ServiceException.INVALID_REQUEST("folders and tags must be retrieved from cache", null);
/*      */     }
/*      */     
/*      */ 
/* 2721 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 2722 */     PreparedStatement stmt = null;
/*      */     try {
/* 2724 */       String typeConstraint = type == MailItem.Type.UNKNOWN ? "type NOT IN " + NON_SYNCABLE_TYPES : typeIn(type);
/*      */       
/* 2726 */       String dateConstraint = changeDate > 0 ? "change_date > ? AND " : "";
/* 2727 */       stmt = conn.prepareStatement("SELECT id, type, folder_id, uuid FROM " + getMailItemTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + dateConstraint + typeConstraint + " ORDER BY mod_metadata, id");
/*      */       
/*      */ 
/*      */ 
/* 2731 */       if (type == MailItem.Type.MESSAGE) {
/* 2732 */         Db.getInstance().enableStreaming(stmt);
/*      */       }
/* 2734 */       int pos = 1;
/* 2735 */       pos = setMailboxId(stmt, mbox, pos);
/* 2736 */       if (changeDate > 0) {
/* 2737 */         stmt.setInt(pos++, changeDate);
/*      */       }
/* 2739 */       return populateWithResultSetData(visible, stmt);
/*      */     } catch (SQLException e) {
/* 2741 */       throw ServiceException.FAILURE("Getting items modified since " + changeDate, e);
/*      */     } finally {
/* 2743 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   private static final int LEAF_CI_IS_UNREAD = 4;
/*      */   
/*      */   private static final int LEAF_CI_FOLDER_ID = 5;
/*      */   
/*      */   private static final int LEAF_CI_PARENT_ID = 6;
/*      */   
/*      */   private static final int LEAF_CI_BLOB_DIGEST = 7;
/*      */   private static Pair<List<Integer>, TypedIdList> populateWithResultSetData(Set<Integer> visible, PreparedStatement stmt)
/*      */     throws SQLException, ServiceException
/*      */   {
/* 2758 */     List<Integer> modified = new ArrayList();
/* 2759 */     TypedIdList missed = new TypedIdList();
/* 2760 */     ResultSet rs = null;
/*      */     try {
/* 2762 */       rs = stmt.executeQuery();
/* 2763 */       while (rs.next()) {
/* 2764 */         if ((visible == null) || (visible.contains(Integer.valueOf(rs.getInt(3))))) {
/* 2765 */           modified.add(Integer.valueOf(rs.getInt(1)));
/*      */         } else {
/* 2767 */           missed.add(MailItem.Type.of(rs.getByte(2)), Integer.valueOf(rs.getInt(1)), rs.getString(4));
/*      */         }
/*      */       }
/*      */     }
/*      */     finally {
/* 2772 */       DbPool.closeResults(rs);
/*      */     }
/* 2774 */     return new Pair(modified, missed);
/*      */   }
/*      */   
/*      */   public static void completeConversation(Mailbox mbox, DbPool.DbConnection conn, MailItem.UnderlyingData data) throws ServiceException
/*      */   {
/* 2779 */     completeConversations(mbox, conn, Collections.singletonList(data));
/*      */   }
/*      */   
/*      */   private static void completeConversations(Mailbox mbox, DbPool.DbConnection conn, List<MailItem.UnderlyingData> convData) throws ServiceException
/*      */   {
/* 2784 */     if ((convData == null) || (convData.isEmpty())) {
/* 2785 */       return;
/*      */     }
/*      */     
/* 2788 */     for (MailItem.UnderlyingData data : convData) {
/* 2789 */       if (data.type != MailItem.Type.CONVERSATION.toByte()) {
/* 2790 */         throw ServiceException.FAILURE("attempting to complete a non-conversation", null);
/*      */       }
/*      */     }
/*      */     
/* 2794 */     Map<Integer, MailItem.UnderlyingData> conversations = new HashMap(Db.getINClauseBatchSize() * 3 / 2);
/*      */     
/* 2796 */     PreparedStatement stmt = null;
/* 2797 */     ResultSet rs = null;
/* 2798 */     for (int i = 0; i < convData.size(); i += Db.getINClauseBatchSize()) {
/*      */       try {
/* 2800 */         int count = Math.min(Db.getINClauseBatchSize(), convData.size() - i);
/* 2801 */         stmt = conn.prepareStatement("SELECT parent_id, unread, flags, tag_names FROM " + getMailItemTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + DbUtil.whereIn("parent_id", count));
/*      */         
/*      */ 
/* 2804 */         int pos = 1;
/* 2805 */         pos = setMailboxId(stmt, mbox, pos);
/* 2806 */         for (int index = i; index < i + count; index++) {
/* 2807 */           MailItem.UnderlyingData data = (MailItem.UnderlyingData)convData.get(index);
/* 2808 */           stmt.setInt(pos++, data.id);
/* 2809 */           conversations.put(Integer.valueOf(data.id), data);
/*      */           
/* 2811 */           data.unreadCount = 0;
/* 2812 */           data.setFlags(0);
/* 2813 */           data.setTags(null);
/*      */         }
/* 2815 */         rs = stmt.executeQuery();
/*      */         
/* 2817 */         HashMultimap<Integer, String> convTags = HashMultimap.create();
/*      */         
/* 2819 */         while (rs.next()) {
/* 2820 */           Integer convId = Integer.valueOf(rs.getInt(1));
/* 2821 */           MailItem.UnderlyingData data = (MailItem.UnderlyingData)conversations.get(convId);
/* 2822 */           assert (data != null);
/*      */           
/* 2824 */           data.unreadCount += rs.getInt(2);
/* 2825 */           data.setFlags(data.getFlags() | rs.getInt(3));
/*      */           
/* 2827 */           String[] tags = DbTag.deserializeTags(rs.getString(4));
/* 2828 */           if (tags != null) {
/* 2829 */             convTags.putAll(convId, Arrays.asList(tags));
/*      */           }
/*      */         }
/*      */         
/* 2833 */         for (Map.Entry<Integer, Collection<String>> entry : convTags.asMap().entrySet()) {
/* 2834 */           MailItem.UnderlyingData data = (MailItem.UnderlyingData)conversations.get(entry.getKey());
/* 2835 */           if (data != null) {
/* 2836 */             data.setTags(new Tag.NormalizedTags((Collection)entry.getValue()));
/*      */           }
/*      */         }
/*      */       } catch (SQLException e) {
/* 2840 */         throw ServiceException.FAILURE("completing conversation data", e);
/*      */       } finally {
/* 2842 */         DbPool.closeResults(rs);
/* 2843 */         DbPool.closeStatement(stmt);
/*      */       }
/*      */       
/* 2846 */       conversations.clear();
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   private static final int LEAF_CI_MOD_CONTENT = 8;
/*      */   
/*      */   private static final int LEAF_CI_MOD_METADATA = 9;
/*      */   
/*      */   private static final int LEAF_CI_FLAGS = 10;
/*      */   
/*      */   private static final int LEAF_CI_INDEX_ID = 11;
/*      */   
/*      */   private static final int LEAF_CI_LOCATOR = 12;
/*      */   
/*      */   private static final int LEAF_CI_TAGS = 13;
/*      */   
/*      */   private static final int LEAF_CI_UUID = 14;
/*      */   
/*      */   private static final String IMAP_FIELDS = "mi.id, mi.type, mi.imap_id, mi.unread, mi.flags, mi.tag_names";
/*      */   public static MailItem.PendingDelete getLeafNodes(Folder folder)
/*      */     throws ServiceException
/*      */   {
/* 2869 */     Mailbox mbox = folder.getMailbox();
/* 2870 */     int folderId = folder.getId();
/* 2871 */     QueryParams params = new QueryParams();
/* 2872 */     params.setFolderIds(Collections.singletonList(Integer.valueOf(folderId)));
/* 2873 */     MailItem.PendingDelete info = getLeafNodes(mbox, params);
/*      */     
/* 2875 */     info.itemIds.add(folder.getType(), Integer.valueOf(folderId), folder.getUuid());
/* 2876 */     return info;
/*      */   }
/*      */   
/*      */   public static MailItem.PendingDelete getLeafNodes(Mailbox mbox, QueryParams params) throws ServiceException {
/* 2880 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 2881 */     PreparedStatement stmt = null;
/* 2882 */     ResultSet rs = null;
/*      */     try {
/* 2884 */       StringBuilder buf = new StringBuilder();
/* 2885 */       buf.append("SELECT id, size, type, unread, folder_id, parent_id, blob_digest, mod_content, mod_metadata, flags, index_id, locator, tag_names, uuid FROM " + getMailItemTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + "type NOT IN " + FOLDER_TYPES);
/*      */       
/* 2887 */       String whereClause = params.getWhereClause();
/* 2888 */       if (!StringUtil.isNullOrEmpty(whereClause)) {
/* 2889 */         buf.append(" AND ").append(whereClause);
/*      */       }
/* 2891 */       String limitClause = params.getLimitClause();
/* 2892 */       if (!StringUtil.isNullOrEmpty(limitClause)) {
/* 2893 */         buf.append(" ").append(limitClause);
/*      */       }
/* 2895 */       stmt = conn.prepareStatement(buf.toString());
/* 2896 */       Db.getInstance().enableStreaming(stmt);
/* 2897 */       int pos = 1;
/* 2898 */       pos = setMailboxId(stmt, mbox, pos);
/*      */       
/* 2900 */       MailItem.PendingDelete info = accumulateDeletionInfo(mbox, stmt);
/* 2901 */       stmt = null;
/*      */       
/* 2903 */       return info;
/*      */     } catch (SQLException e) {
/* 2905 */       throw ServiceException.FAILURE("fetching list of items to delete", e);
/*      */     } finally {
/* 2907 */       DbPool.closeResults(rs);
/* 2908 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static HashSet<Integer> getItemsWithOutdatedRevisions(Mailbox mbox, int before) throws ServiceException {
/* 2913 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 2914 */     PreparedStatement stmt = null;
/* 2915 */     ResultSet rs = null;
/* 2916 */     HashSet<Integer> outdatedIds = new HashSet();
/*      */     
/* 2918 */     if (before <= 0) {
/* 2919 */       return outdatedIds;
/*      */     }
/*      */     try
/*      */     {
/* 2923 */       StringBuilder constraint = new StringBuilder();
/* 2924 */       String dateColumn = "date";
/*      */       
/* 2926 */       constraint.append(dateColumn).append(" < ? ");
/*      */       
/* 2928 */       String orderByDate = " ORDER BY " + dateColumn;
/*      */       
/* 2930 */       stmt = conn.prepareStatement("SELECT item_id FROM " + getRevisionTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + constraint + orderByDate);
/*      */       
/*      */ 
/*      */ 
/* 2934 */       int pos = 1;
/* 2935 */       pos = setMailboxId(stmt, mbox, pos);
/* 2936 */       stmt.setInt(pos++, before);
/*      */       
/* 2938 */       rs = stmt.executeQuery();
/*      */       
/* 2940 */       while (rs.next()) {
/* 2941 */         outdatedIds.add(Integer.valueOf(rs.getInt(1)));
/*      */       }
/*      */       
/* 2944 */       stmt = null;
/* 2945 */       return outdatedIds;
/*      */     } catch (SQLException e) {
/* 2947 */       throw ServiceException.FAILURE("fetching list of items with outdated revisions for purge", e);
/*      */     } finally {
/* 2949 */       DbPool.closeResults(rs);
/* 2950 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static MailItem.PendingDelete getLeafNodes(Mailbox mbox, List<Folder> folders, int before, boolean globalMessages, Boolean unread, boolean useChangeDate, Integer maxItems)
/*      */     throws ServiceException
/*      */   {
/* 2957 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 2958 */     PreparedStatement stmt = null;
/* 2959 */     ResultSet rs = null;
/* 2960 */     if (folders == null) {
/* 2961 */       folders = Collections.emptyList();
/*      */     }
/*      */     try
/*      */     {
/* 2965 */       StringBuilder constraint = new StringBuilder();
/* 2966 */       String dateColumn = useChangeDate ? "change_date" : "date";
/*      */       
/* 2968 */       if (globalMessages) {
/* 2969 */         constraint.append(dateColumn).append(" < ? AND ").append(typeIn(MailItem.Type.MESSAGE));
/*      */       } else {
/* 2971 */         constraint.append(dateColumn).append(" < ? AND type NOT IN ").append(NON_SEARCHABLE_TYPES);
/* 2972 */         if (!folders.isEmpty()) {
/* 2973 */           constraint.append(" AND ").append(DbUtil.whereIn("folder_id", folders.size()));
/*      */         }
/*      */       }
/* 2976 */       if (unread != null) {
/* 2977 */         constraint.append(" AND unread = ?");
/*      */       }
/* 2979 */       String orderByLimit = "";
/* 2980 */       if ((maxItems != null) && (Db.supports(Db.Capability.LIMIT_CLAUSE))) {
/* 2981 */         orderByLimit = " ORDER BY " + dateColumn + " " + Db.getInstance().limit(maxItems.intValue());
/*      */       }
/*      */       
/* 2984 */       stmt = conn.prepareStatement("SELECT id, size, type, unread, folder_id, parent_id, blob_digest, mod_content, mod_metadata, flags, index_id, locator, tag_names, uuid FROM " + getMailItemTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + constraint + orderByLimit);
/*      */       
/*      */ 
/* 2987 */       if ((globalMessages) || (getTotalFolderSize(folders) > 10000)) {
/* 2988 */         Db.getInstance().enableStreaming(stmt);
/*      */       }
/* 2990 */       int pos = 1;
/* 2991 */       pos = setMailboxId(stmt, mbox, pos);
/* 2992 */       stmt.setInt(pos++, before);
/* 2993 */       Iterator i$; if (!globalMessages)
/* 2994 */         for (i$ = folders.iterator(); i$.hasNext();) { folder = (Folder)i$.next();
/* 2995 */           stmt.setInt(pos++, folder.getId());
/*      */         }
/*      */       Folder folder;
/* 2998 */       if (unread != null) {
/* 2999 */         stmt.setBoolean(pos++, unread.booleanValue());
/*      */       }
/*      */       
/* 3002 */       MailItem.PendingDelete info = accumulateDeletionInfo(mbox, stmt);
/* 3003 */       stmt = null;
/* 3004 */       return info;
/*      */     } catch (SQLException e) {
/* 3006 */       throw ServiceException.FAILURE("fetching list of items for purge", e);
/*      */     } finally {
/* 3008 */       DbPool.closeResults(rs);
/* 3009 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   static MailItem.PendingDelete accumulateDeletionInfo(Mailbox mbox, PreparedStatement stmt)
/*      */     throws ServiceException
/*      */   {
/* 3017 */     ResultSet rs = null;
/*      */     try {
/* 3019 */       rs = stmt.executeQuery();
/*      */       
/* 3021 */       MailItem.PendingDelete info = new MailItem.PendingDelete();
/* 3022 */       info.size = 0L;
/*      */       
/* 3024 */       List<Integer> versionedIds = accumulateLeafNodes(info, mbox, rs);
/* 3025 */       rs.close();
/* 3026 */       rs = null;
/* 3027 */       stmt.close();
/* 3028 */       stmt = null;
/*      */       
/* 3030 */       accumulateLeafRevisions(info, mbox, versionedIds);
/* 3031 */       accumulateComments(info, mbox);
/*      */       
/* 3033 */       return info;
/*      */     } catch (SQLException e) {
/* 3035 */       throw ServiceException.FAILURE("accumulating deletion info", e);
/*      */     } finally {
/* 3037 */       DbPool.closeResults(rs);
/* 3038 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   static int getTotalFolderSize(Collection<Folder> folders) {
/* 3043 */     int totalSize = 0;
/* 3044 */     if (folders != null) {
/* 3045 */       for (Folder folder : folders) {
/* 3046 */         totalSize = (int)(totalSize + folder.getSize());
/*      */       }
/*      */     }
/* 3049 */     return totalSize;
/*      */   }
/*      */   
/*      */   public static class LocationCount {
/*      */     public int count;
/*      */     public int deleted;
/*      */     public long size;
/*      */     
/*      */     public LocationCount(int c, int d, long sz) {
/* 3058 */       this.count = c;
/* 3059 */       this.deleted = d;
/* 3060 */       this.size = sz;
/*      */     }
/*      */     
/*      */     public LocationCount(LocationCount lc) {
/* 3064 */       this(lc.count, lc.deleted, lc.size);
/*      */     }
/*      */     
/*      */     public LocationCount increment(int c, int d, long sz) {
/* 3068 */       this.count += c;
/* 3069 */       this.deleted += d;
/* 3070 */       this.size += sz;
/* 3071 */       return this;
/*      */     }
/*      */     
/*      */     public LocationCount increment(LocationCount lc) {
/* 3075 */       return increment(lc.count, lc.deleted, lc.size);
/*      */     }
/*      */     
/*      */     public String toString()
/*      */     {
/* 3080 */       return this.count + (this.deleted > 0 ? " / -" + this.deleted : "") + " [" + this.size + " bytes]";
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   static List<Integer> accumulateLeafNodes(MailItem.PendingDelete info, Mailbox mbox, ResultSet rs)
/*      */     throws SQLException, ServiceException
/*      */   {
/* 3090 */     boolean dumpsterEnabled = mbox.dumpsterEnabled();
/* 3091 */     boolean useDumpsterForSpam = mbox.useDumpsterForSpam();
/* 3092 */     StoreManager sm = StoreManager.getInstance();
/* 3093 */     List<Integer> versioned = new ArrayList();
/*      */     
/* 3095 */     while (rs.next())
/*      */     {
/* 3097 */       int revision = rs.getInt(8);
/* 3098 */       int modMetadata = rs.getInt(9);
/* 3099 */       if (!mbox.checkItemChangeID(modMetadata, revision)) {
/* 3100 */         info.incomplete = true;
/*      */       }
/*      */       else
/*      */       {
/* 3104 */         int id = rs.getInt(1);
/* 3105 */         String uuid = rs.getString(14);
/* 3106 */         long size = rs.getLong(2);
/* 3107 */         MailItem.Type type = MailItem.Type.of(rs.getByte(3));
/*      */         
/* 3109 */         Integer itemId = Integer.valueOf(id);
/* 3110 */         info.itemIds.add(type, itemId, uuid);
/* 3111 */         info.size += size;
/*      */         
/* 3113 */         if (rs.getBoolean(4)) {
/* 3114 */           info.unreadIds.add(itemId);
/*      */         }
/* 3116 */         boolean isMessage = false;
/* 3117 */         switch (type) {
/*      */         case CONTACT: 
/* 3119 */           info.contacts += 1;
/* 3120 */           break;
/*      */         case MESSAGE: 
/*      */         case CHAT: 
/* 3123 */           isMessage = true;
/*      */         }
/*      */         
/*      */         
/*      */ 
/* 3128 */         if (isMessage) {
/* 3129 */           int parentId = rs.getInt(6);
/* 3130 */           if ((rs.wasNull()) || (parentId <= 0))
/*      */           {
/* 3132 */             info.itemIds.add(MailItem.Type.VIRTUAL_CONVERSATION, Integer.valueOf(-id), null);
/*      */           } else {
/* 3134 */             info.modifiedIds.add(Integer.valueOf(parentId));
/*      */           }
/*      */         }
/*      */         
/* 3138 */         int flags = rs.getInt(10);
/* 3139 */         if ((flags & Flag.BITMASK_VERSIONED) != 0) {
/* 3140 */           versioned.add(Integer.valueOf(id));
/*      */         }
/*      */         
/* 3143 */         Integer folderId = Integer.valueOf(rs.getInt(5));
/* 3144 */         boolean isDeleted = (flags & Flag.BITMASK_DELETED) != 0;
/* 3145 */         LocationCount fcount = (LocationCount)info.folderCounts.get(folderId);
/* 3146 */         if (fcount == null) {
/* 3147 */           info.folderCounts.put(folderId, new LocationCount(1, isDeleted ? 1 : 0, size));
/*      */         } else {
/* 3149 */           fcount.increment(1, isDeleted ? 1 : 0, size);
/*      */         }
/*      */         
/* 3152 */         String[] tags = DbTag.deserializeTags(rs.getString(13));
/* 3153 */         if (tags != null) {
/* 3154 */           for (String tag : tags) {
/* 3155 */             LocationCount tcount = (LocationCount)info.tagCounts.get(tag);
/* 3156 */             if (tcount == null) {
/* 3157 */               info.tagCounts.put(tag, new LocationCount(1, isDeleted ? 1 : 0, size));
/*      */             } else {
/* 3159 */               tcount.increment(1, isDeleted ? 1 : 0, size);
/*      */             }
/*      */           }
/*      */         }
/*      */         
/* 3164 */         int fid = folderId != null ? folderId.intValue() : -1;
/* 3165 */         if ((!dumpsterEnabled) || (fid == 6) || ((fid == 4) && (!useDumpsterForSpam))) {
/* 3166 */           String blobDigest = rs.getString(7);
/* 3167 */           if (blobDigest != null) {
/* 3168 */             info.blobDigests.add(blobDigest);
/* 3169 */             String locator = rs.getString(12);
/*      */             try {
/* 3171 */               MailboxBlob mblob = sm.getMailboxBlob(mbox, id, revision, locator);
/* 3172 */               if (mblob == null) {
/* 3173 */                 ZimbraLog.mailbox.warn("missing blob for id: %d, change: %d", new Object[] { Integer.valueOf(id), Integer.valueOf(revision) });
/*      */               } else {
/* 3175 */                 info.blobs.add(mblob);
/*      */               }
/*      */             } catch (Exception e1) {
/* 3178 */               ZimbraLog.mailbox.warn("Exception while getting mailbox blob", e1);
/*      */             }
/*      */           }
/*      */           
/* 3182 */           int indexId = rs.getInt(11);
/* 3183 */           boolean indexed = !rs.wasNull();
/* 3184 */           if (indexed) {
/* 3185 */             if (info.sharedIndex == null) {
/* 3186 */               info.sharedIndex = new HashSet();
/*      */             }
/* 3188 */             boolean shared = (flags & Flag.BITMASK_COPIED) != 0;
/* 3189 */             if (shared) {
/* 3190 */               info.sharedIndex.add(Integer.valueOf(indexId));
/*      */             } else {
/* 3192 */               info.indexIds.add(Integer.valueOf(indexId > MailItem.IndexStatus.STALE.id() ? indexId : id));
/*      */             }
/*      */           }
/*      */         }
/*      */       }
/*      */     }
/* 3198 */     return versioned;
/*      */   }
/*      */   
/*      */   static void accumulateLeafRevisions(MailItem.PendingDelete info, Mailbox mbox, List<Integer> versioned) throws ServiceException {
/* 3202 */     if ((versioned == null) || (versioned.size() == 0)) {
/* 3203 */       return;
/*      */     }
/* 3205 */     boolean dumpsterEnabled = mbox.dumpsterEnabled();
/* 3206 */     boolean useDumpsterForSpam = mbox.useDumpsterForSpam();
/* 3207 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 3208 */     StoreManager sm = StoreManager.getInstance();
/*      */     
/* 3210 */     PreparedStatement stmt = null;
/* 3211 */     ResultSet rs = null;
/*      */     try {
/* 3213 */       stmt = conn.prepareStatement("SELECT mi.id, mi.folder_id, rev.size, rev.mod_content, rev.locator, rev.blob_digest  FROM " + getMailItemTableName(mbox, "mi") + ", " + getRevisionTableName(mbox, "rev") + " WHERE mi.id = rev.item_id AND " + DbUtil.whereIn("mi.id", versioned.size()) + (DebugConfig.disableMailboxGroups ? "" : " AND mi.mailbox_id = ? AND mi.mailbox_id = rev.mailbox_id"));
/*      */       
/*      */ 
/*      */ 
/* 3217 */       int pos = 1;
/* 3218 */       for (Iterator i$ = versioned.iterator(); i$.hasNext();) { int vid = ((Integer)i$.next()).intValue();
/* 3219 */         stmt.setInt(pos++, vid);
/*      */       }
/* 3221 */       pos = setMailboxId(stmt, mbox, pos);
/* 3222 */       rs = stmt.executeQuery();
/*      */       
/* 3224 */       while (rs.next()) {
/* 3225 */         Integer folderId = Integer.valueOf(rs.getInt(2));
/* 3226 */         LocationCount count = (LocationCount)info.folderCounts.get(folderId);
/* 3227 */         if (count == null) {
/* 3228 */           info.folderCounts.put(folderId, new LocationCount(0, 0, rs.getLong(3)));
/*      */         } else {
/* 3230 */           count.increment(0, 0, rs.getLong(3));
/*      */         }
/*      */         
/* 3233 */         int fid = folderId != null ? folderId.intValue() : -1;
/* 3234 */         if ((!dumpsterEnabled) || (fid == 6) || ((fid == 4) && (!useDumpsterForSpam))) {
/* 3235 */           String blobDigest = rs.getString(6);
/* 3236 */           if (blobDigest != null) {
/* 3237 */             info.blobDigests.add(blobDigest);
/*      */             try {
/* 3239 */               MailboxBlob mblob = sm.getMailboxBlob(mbox, rs.getInt(1), rs.getInt(4), rs.getString(5));
/* 3240 */               if (mblob == null) {
/* 3241 */                 ZimbraLog.mailbox.error("missing blob for id: %d, change: %s", new Object[] { Integer.valueOf(rs.getInt(1)), Integer.valueOf(rs.getInt(4)) });
/*      */               }
/*      */               else {
/* 3244 */                 info.blobs.add(mblob);
/*      */               }
/*      */             } catch (Exception e1) {}
/*      */           }
/*      */         }
/* 3249 */         long revisionSize = rs.getLong(3);
/* 3250 */         info.size += revisionSize;
/*      */       }
/*      */     } catch (SQLException e) {
/* 3253 */       throw ServiceException.FAILURE("getting version deletion info for items: " + versioned, e);
/*      */     } finally {
/* 3255 */       DbPool.closeResults(rs);
/* 3256 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   static void accumulateComments(MailItem.PendingDelete info, Mailbox mbox) throws ServiceException {
/* 3261 */     List<Integer> documents = info.itemIds.getIds(MailItem.Type.DOCUMENT);
/* 3262 */     if ((documents == null) || (documents.size() == 0)) {
/* 3263 */       return;
/*      */     }
/* 3265 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 3266 */     PreparedStatement stmt = null;
/* 3267 */     ResultSet rs = null;
/*      */     try {
/* 3269 */       stmt = conn.prepareStatement("SELECT type, id, uuid  FROM " + getMailItemTableName(mbox) + " WHERE " + DbUtil.whereIn("parent_id", documents.size()) + (DebugConfig.disableMailboxGroups ? "" : " AND mailbox_id = ?"));
/*      */       
/*      */ 
/*      */ 
/* 3273 */       int pos = 1;
/* 3274 */       for (Iterator i$ = documents.iterator(); i$.hasNext();) { int id = ((Integer)i$.next()).intValue();
/* 3275 */         stmt.setInt(pos++, id);
/*      */       }
/* 3277 */       pos = setMailboxId(stmt, mbox, pos);
/* 3278 */       rs = stmt.executeQuery();
/*      */       
/* 3280 */       while (rs.next()) {
/* 3281 */         info.itemIds.add(MailItem.Type.of(rs.getByte(1)), Integer.valueOf(rs.getInt(2)), rs.getString(3));
/*      */       }
/*      */     } catch (SQLException e) {
/* 3284 */       throw ServiceException.FAILURE("getting Comment deletion info for items: " + documents, e);
/*      */     } finally {
/* 3286 */       DbPool.closeResults(rs);
/* 3287 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public static String getBlobDigest(Mailbox mbox, int itemId)
/*      */     throws ServiceException
/*      */   {
/* 3296 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 3297 */     PreparedStatement stmt = null;
/* 3298 */     ResultSet rs = null;
/*      */     try {
/* 3300 */       stmt = conn.prepareStatement("SELECT blob_digest  FROM " + getMailItemTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */       
/*      */ 
/* 3303 */       int pos = 1;
/* 3304 */       pos = setMailboxId(stmt, mbox, pos);
/* 3305 */       stmt.setInt(pos++, itemId);
/* 3306 */       rs = stmt.executeQuery();
/*      */       
/* 3308 */       return rs.next() ? rs.getString(1) : null;
/*      */     } catch (SQLException e) {
/* 3310 */       throw ServiceException.FAILURE("unable to get blob digest for id " + itemId, e);
/*      */     } finally {
/* 3312 */       DbPool.closeResults(rs);
/* 3313 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void resolveSharedIndex(Mailbox mbox, MailItem.PendingDelete info) throws ServiceException {
/* 3318 */     if ((info.sharedIndex == null) || (info.sharedIndex.isEmpty())) {
/* 3319 */       return;
/*      */     }
/* 3321 */     List<Integer> indexIDs = new ArrayList(info.sharedIndex);
/*      */     
/* 3323 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 3324 */     PreparedStatement stmt = null;
/* 3325 */     ResultSet rs = null;
/*      */     try {
/* 3327 */       for (int i = 0; i < indexIDs.size(); i += Db.getINClauseBatchSize()) {
/* 3328 */         int count = Math.min(Db.getINClauseBatchSize(), indexIDs.size() - i);
/* 3329 */         stmt = conn.prepareStatement("SELECT index_id FROM " + getMailItemTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + DbUtil.whereIn("index_id", count));
/*      */         
/* 3331 */         int pos = 1;
/* 3332 */         pos = setMailboxId(stmt, mbox, pos);
/* 3333 */         for (int index = i; index < i + count; index++) {
/* 3334 */           stmt.setInt(pos++, ((Integer)indexIDs.get(index)).intValue());
/*      */         }
/* 3336 */         rs = stmt.executeQuery();
/* 3337 */         while (rs.next()) {
/* 3338 */           info.sharedIndex.remove(Integer.valueOf(rs.getInt(1)));
/*      */         }
/* 3340 */         rs.close();rs = null;
/* 3341 */         stmt.close();stmt = null;
/*      */       }
/*      */       
/* 3344 */       info.indexIds.addAll(info.sharedIndex);
/* 3345 */       info.sharedIndex.clear();
/*      */     } catch (SQLException e) {
/* 3347 */       throw ServiceException.FAILURE("resolving shared index entries", e);
/*      */     } finally {
/* 3349 */       DbPool.closeResults(rs);
/* 3350 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/* 3357 */   static final String IMAP_TYPES = "(" + MailItem.Type.MESSAGE.toByte() + "," + MailItem.Type.CHAT.toByte() + ',' + MailItem.Type.CONTACT.toByte() + ")";
/*      */   public static final int CI_ID = 1;
/*      */   public static final int CI_TYPE = 2;
/*      */   
/*      */   public static List<ImapMessage> loadImapFolder(Folder folder) throws ServiceException
/*      */   {
/* 3363 */     Mailbox mbox = folder.getMailbox();
/* 3364 */     List<ImapMessage> result = new ArrayList();
/*      */     
/* 3366 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 3367 */     PreparedStatement stmt = null;
/* 3368 */     ResultSet rs = null;
/*      */     try {
/* 3370 */       stmt = conn.prepareStatement("SELECT mi.id, mi.type, mi.imap_id, mi.unread, mi.flags, mi.tag_names FROM " + getMailItemTableName(folder.getMailbox(), " mi") + " WHERE " + IN_THIS_MAILBOX_AND + "folder_id = ? AND type IN " + IMAP_TYPES);
/*      */       
/*      */ 
/* 3373 */       if (folder.getSize() > 10000L) {
/* 3374 */         Db.getInstance().enableStreaming(stmt);
/*      */       }
/* 3376 */       int pos = 1;
/* 3377 */       pos = setMailboxId(stmt, mbox, pos);
/* 3378 */       stmt.setInt(pos++, folder.getId());
/* 3379 */       rs = stmt.executeQuery();
/*      */       int flags;
/* 3381 */       while (rs.next()) {
/* 3382 */         flags = rs.getBoolean(4) ? Flag.BITMASK_UNREAD | rs.getInt(5) : rs.getInt(5);
/* 3383 */         result.add(new ImapMessage(rs.getInt(1), MailItem.Type.of(rs.getByte(2)), rs.getInt(3), flags, DbTag.deserializeTags(rs.getString(6))));
/*      */       }
/* 3385 */       return result;
/*      */     } catch (SQLException e) {
/* 3387 */       throw ServiceException.FAILURE("loading IMAP folder data: " + folder.getPath(), e);
/*      */     } finally {
/* 3389 */       DbPool.closeResults(rs);
/* 3390 */       DbPool.closeStatement(stmt); } }
/*      */   
/*      */   public static final int CI_PARENT_ID = 3;
/*      */   public static final int CI_FOLDER_ID = 4;
/*      */   public static final int CI_PREV_FOLDERS = 5;
/* 3395 */   public static int countImapRecent(Folder folder, int uidCutoff) throws ServiceException { Mailbox mbox = folder.getMailbox();
/*      */     
/* 3397 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 3398 */     PreparedStatement stmt = null;
/* 3399 */     ResultSet rs = null;
/*      */     try {
/* 3401 */       stmt = conn.prepareStatement("SELECT COUNT(*) FROM " + getMailItemTableName(folder.getMailbox()) + " WHERE " + IN_THIS_MAILBOX_AND + "folder_id = ? AND type IN " + IMAP_TYPES + " AND (imap_id IS NULL OR imap_id = 0 OR imap_id > ?)");
/*      */       
/*      */ 
/* 3404 */       int pos = 1;
/* 3405 */       pos = setMailboxId(stmt, mbox, pos);
/* 3406 */       stmt.setInt(pos++, folder.getId());
/* 3407 */       stmt.setInt(pos++, uidCutoff);
/* 3408 */       rs = stmt.executeQuery();
/*      */       
/* 3410 */       return rs.next() ? rs.getInt(1) : 0;
/*      */     } catch (SQLException e) {
/* 3412 */       throw ServiceException.FAILURE("counting IMAP \\Recent messages: " + folder.getPath(), e);
/*      */     } finally {
/* 3414 */       DbPool.closeResults(rs);
/* 3415 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static List<Pop3Message> loadPop3Folder(Set<Folder> folders, Date popSince) throws ServiceException {
/* 3420 */     assert (!folders.isEmpty()) : folders;
/* 3421 */     Mailbox mbox = ((Folder)Iterables.get(folders, 0)).getMailbox();
/* 3422 */     long popDate = popSince == null ? -1L : Math.max(popSince.getTime(), -1L);
/* 3423 */     List<Pop3Message> result = new ArrayList();
/*      */     
/* 3425 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 3426 */     PreparedStatement stmt = null;
/* 3427 */     ResultSet rs = null;
/*      */     try {
/* 3429 */       String dateConstraint = popDate < 0L ? "" : " AND date > ?";
/* 3430 */       stmt = conn.prepareStatement("SELECT mi.id, mi.size, mi.blob_digest FROM " + getMailItemTableName(mbox, " mi") + " WHERE " + IN_THIS_MAILBOX_AND + DbUtil.whereIn("folder_id", folders.size()) + " AND type = " + MailItem.Type.MESSAGE.toByte() + " AND " + Db.getInstance().bitAND("flags", String.valueOf(Flag.BITMASK_DELETED | Flag.BITMASK_POPPED)) + " = 0" + dateConstraint);
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 3436 */       if (getTotalFolderSize(folders) > 10000)
/*      */       {
/* 3438 */         Db.getInstance().enableStreaming(stmt);
/*      */       }
/*      */       
/* 3441 */       int pos = 1;
/* 3442 */       pos = setMailboxId(stmt, mbox, pos);
/* 3443 */       for (Folder folder : folders) {
/* 3444 */         stmt.setInt(pos++, folder.getId());
/*      */       }
/* 3446 */       if (popDate >= 0L) {
/* 3447 */         stmt.setInt(pos++, (int)(popDate / 1000L));
/*      */       }
/* 3449 */       rs = stmt.executeQuery();
/*      */       
/* 3451 */       while (rs.next()) {
/* 3452 */         result.add(new Pop3Message(rs.getInt(1), rs.getLong(2), rs.getString(3)));
/*      */       }
/* 3454 */       return result;
/*      */     } catch (SQLException e) {
/* 3456 */       throw ServiceException.FAILURE("loading POP3 folder data: " + folders, e);
/*      */     } finally {
/* 3458 */       DbPool.closeResults(rs);
/* 3459 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static List<MailItem.UnderlyingData> getRevisionInfo(MailItem item, boolean fromDumpster) throws ServiceException {
/* 3464 */     Mailbox mbox = item.getMailbox();
/* 3465 */     List<MailItem.UnderlyingData> dlist = new ArrayList();
/* 3466 */     if (!item.isTagged(Flag.FlagInfo.VERSIONED)) {
/* 3467 */       return dlist;
/*      */     }
/* 3469 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 3470 */     PreparedStatement stmt = null;
/* 3471 */     ResultSet rs = null;
/*      */     try {
/* 3473 */       stmt = conn.prepareStatement("SELECT date, size, locator, blob_digest, name, metadata, mod_metadata, change_date, mod_content FROM " + getRevisionTableName(mbox, fromDumpster) + " WHERE " + IN_THIS_MAILBOX_AND + "item_id = ?" + " ORDER BY version");
/*      */       
/*      */ 
/* 3476 */       int pos = 1;
/* 3477 */       pos = setMailboxId(stmt, mbox, pos);
/* 3478 */       stmt.setInt(pos++, item.getId());
/* 3479 */       rs = stmt.executeQuery();
/*      */       
/* 3481 */       while (rs.next()) {
/* 3482 */         dlist.add(constructRevision(rs, item, fromDumpster));
/*      */       }
/* 3484 */       return dlist;
/*      */     } catch (SQLException e) {
/* 3486 */       throw ServiceException.FAILURE("getting old revisions for item: " + item.getId(), e);
/*      */     } finally {
/* 3488 */       DbPool.closeResults(rs);
/* 3489 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static List<Integer> listByFolder(Folder folder, MailItem.Type type, boolean descending) throws ServiceException {
/* 3494 */     Mailbox mbox = folder.getMailbox();
/* 3495 */     boolean allTypes = type == MailItem.Type.UNKNOWN;
/* 3496 */     List<Integer> result = new ArrayList();
/*      */     
/* 3498 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 3499 */     PreparedStatement stmt = null;
/* 3500 */     ResultSet rs = null;
/*      */     try {
/* 3502 */       String typeConstraint = allTypes ? "" : "type = ? AND ";
/* 3503 */       stmt = conn.prepareStatement("SELECT id FROM " + getMailItemTableName(folder) + " WHERE " + IN_THIS_MAILBOX_AND + typeConstraint + "folder_id = ?" + " ORDER BY date" + (descending ? " DESC" : ""));
/*      */       
/*      */ 
/* 3506 */       if ((type == MailItem.Type.MESSAGE) && (folder.getSize() > 10000L)) {
/* 3507 */         Db.getInstance().enableStreaming(stmt);
/*      */       }
/* 3509 */       int pos = 1;
/* 3510 */       pos = setMailboxId(stmt, mbox, pos);
/* 3511 */       if (!allTypes) {
/* 3512 */         stmt.setByte(pos++, type.toByte());
/*      */       }
/* 3514 */       stmt.setInt(pos++, folder.getId());
/* 3515 */       rs = stmt.executeQuery();
/*      */       
/* 3517 */       while (rs.next()) {
/* 3518 */         result.add(Integer.valueOf(rs.getInt(1)));
/*      */       }
/* 3520 */       return result;
/*      */     } catch (SQLException e) {
/* 3522 */       throw ServiceException.FAILURE("fetching item list for folder " + folder.getId(), e);
/*      */     } finally {
/* 3524 */       DbPool.closeResults(rs);
/* 3525 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static TypedIdList listByFolder(Folder folder, boolean descending) throws ServiceException {
/* 3530 */     Mailbox mbox = folder.getMailbox();
/* 3531 */     TypedIdList result = new TypedIdList();
/*      */     
/* 3533 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 3534 */     PreparedStatement stmt = null;
/* 3535 */     ResultSet rs = null;
/*      */     try {
/* 3537 */       stmt = conn.prepareStatement("SELECT id, type, uuid FROM " + getMailItemTableName(folder) + " WHERE " + IN_THIS_MAILBOX_AND + "folder_id = ?" + " ORDER BY date" + (descending ? " DESC" : ""));
/*      */       
/*      */ 
/* 3540 */       int pos = 1;
/* 3541 */       pos = setMailboxId(stmt, mbox, pos);
/* 3542 */       stmt.setInt(pos++, folder.getId());
/* 3543 */       rs = stmt.executeQuery();
/*      */       
/* 3545 */       while (rs.next()) {
/* 3546 */         result.add(MailItem.Type.of(rs.getByte(2)), Integer.valueOf(rs.getInt(1)), rs.getString(3));
/*      */       }
/* 3548 */       return result;
/*      */     } catch (SQLException e) {
/* 3550 */       throw ServiceException.FAILURE("fetching item list for folder " + folder.getId(), e);
/*      */     } finally {
/* 3552 */       DbPool.closeResults(rs);
/* 3553 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static SpoolingCache<MailboxBlob.MailboxBlobInfo> getAllBlobs(DbPool.DbConnection conn, int groupId, int volumeId, int lastSyncDate, int currentSyncDate) throws ServiceException
/*      */   {
/* 3559 */     SpoolingCache<MailboxBlob.MailboxBlobInfo> blobs = new SpoolingCache(5000);
/* 3560 */     PreparedStatement stmt = null;
/*      */     try {
/* 3562 */       boolean[] dumpsterOrNot = { false, true };
/* 3563 */       for (boolean fromDumpster : dumpsterOrNot) {
/* 3564 */         String query = "SELECT " + (DebugConfig.disableMailboxGroups ? Integer.valueOf(groupId) : "mailbox_id") + ", id, mod_content," + " locator, blob_digest FROM " + getMailItemTableName(groupId, fromDumpster) + " WHERE blob_digest IS NOT NULL " + (currentSyncDate > 0 ? " AND ((date >= ? AND date < ?) OR (change_date >= ? AND change_date < ?))" : "") + (volumeId > -1 ? " AND locator = ?" : "");
/*      */         
/*      */ 
/*      */ 
/* 3568 */         stmt = conn.prepareStatement(query);
/* 3569 */         getAllBlobs(stmt, volumeId, lastSyncDate, currentSyncDate, blobs);
/*      */         
/* 3571 */         query = "SELECT " + (DebugConfig.disableMailboxGroups ? Integer.valueOf(groupId) : "mailbox_id") + ", item_id, mod_content," + " locator, blob_digest FROM " + getRevisionTableName(groupId, fromDumpster) + " WHERE blob_digest IS NOT NULL " + (currentSyncDate > 0 ? " AND ((date >= ? AND date < ?) OR (change_date >= ? AND change_date < ?))" : "") + (volumeId > -1 ? " AND locator = ?" : "");
/*      */         
/*      */ 
/*      */ 
/* 3575 */         stmt = conn.prepareStatement(query);
/* 3576 */         getAllBlobs(stmt, volumeId, lastSyncDate, currentSyncDate, blobs);
/*      */       }
/* 3578 */       ZimbraLog.mailbox.info("got blob list for group %d volume %d (%d blobs)", new Object[] { Integer.valueOf(groupId), Integer.valueOf(volumeId), Integer.valueOf(blobs.size()) });
/* 3579 */       return blobs;
/*      */     } catch (SQLException e) {
/* 3581 */       throw ServiceException.FAILURE("fetching blob list for group " + groupId, e);
/*      */     } catch (IOException e) {
/* 3583 */       throw ServiceException.FAILURE("fetching blob list for group " + groupId, e);
/*      */     } finally {
/* 3585 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static final int CI_INDEX_ID = 6;
/*      */   public static final int CI_IMAP_ID = 7;
/*      */   public static final int CI_DATE = 8;
/*      */   public static final int CI_SIZE = 9;
/*      */   public static final int CI_LOCATOR = 10;
/*      */   public static final int CI_BLOB_DIGEST = 11;
/*      */   public static SpoolingCache<MailboxBlob.MailboxBlobInfo> getAllBlobs(Mailbox mbox) throws ServiceException {
/* 3596 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 3597 */     return getAllBlobs(conn, mbox);
/*      */   }
/*      */   
/*      */   public static SpoolingCache<MailboxBlob.MailboxBlobInfo> getAllBlobs(DbPool.DbConnection conn, Mailbox mbox) throws ServiceException {
/* 3601 */     SpoolingCache<MailboxBlob.MailboxBlobInfo> blobs = new SpoolingCache(5000);
/*      */     
/* 3603 */     PreparedStatement stmt = null;
/*      */     try {
/* 3605 */       stmt = conn.prepareStatement("SELECT id, mod_content, locator, blob_digest FROM " + getMailItemTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + "blob_digest IS NOT NULL AND locator IS NOT NULL");
/*      */       
/* 3607 */       getAllBlobs(stmt, mbox.getAccountId(), mbox.getId(), blobs);
/* 3608 */       stmt.close();
/* 3609 */       stmt = null;
/*      */       
/* 3611 */       stmt = conn.prepareStatement("SELECT id, mod_content, locator, blob_digest FROM " + getMailItemTableName(mbox, true) + " WHERE " + IN_THIS_MAILBOX_AND + "blob_digest IS NOT NULL AND locator IS NOT NULL");
/*      */       
/* 3613 */       getAllBlobs(stmt, mbox.getAccountId(), mbox.getId(), blobs);
/* 3614 */       stmt.close();
/* 3615 */       stmt = null;
/*      */       
/* 3617 */       stmt = conn.prepareStatement("SELECT item_id, mod_content, locator, blob_digest FROM " + getRevisionTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + "blob_digest IS NOT NULL AND locator IS NOT NULL");
/*      */       
/* 3619 */       getAllBlobs(stmt, mbox.getAccountId(), mbox.getId(), blobs);
/* 3620 */       stmt.close();
/* 3621 */       stmt = null;
/*      */       
/* 3623 */       stmt = conn.prepareStatement("SELECT item_id, mod_content, locator, blob_digest FROM " + getRevisionTableName(mbox, true) + " WHERE " + IN_THIS_MAILBOX_AND + "blob_digest IS NOT NULL AND locator IS NOT NULL");
/*      */       
/* 3625 */       getAllBlobs(stmt, mbox.getAccountId(), mbox.getId(), blobs);
/*      */       
/* 3627 */       ZimbraLog.mailbox.info("got blob list for mailbox %d (%d blobs)", new Object[] { Integer.valueOf(mbox.getId()), Integer.valueOf(blobs.size()) });
/*      */       
/* 3629 */       return blobs;
/*      */     } catch (SQLException e) {
/* 3631 */       throw ServiceException.FAILURE("fetching blob list for mailbox " + mbox.getId(), e);
/*      */     } catch (IOException e) {
/* 3633 */       throw ServiceException.FAILURE("fetching blob list for mailbox " + mbox.getId(), e);
/*      */     } finally {
/* 3635 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   private static void getAllBlobs(PreparedStatement stmt, int volumeId, int lastSyncDate, int currentSyncDate, SpoolingCache<MailboxBlob.MailboxBlobInfo> blobs) throws ServiceException, SQLException, IOException
/*      */   {
/* 3641 */     ResultSet rs = null;
/*      */     try {
/* 3643 */       int pos = 1;
/* 3644 */       if (currentSyncDate > 0) {
/* 3645 */         stmt.setInt(pos++, lastSyncDate);
/* 3646 */         stmt.setInt(pos++, currentSyncDate);
/* 3647 */         stmt.setInt(pos++, lastSyncDate);
/* 3648 */         stmt.setInt(pos++, currentSyncDate);
/*      */       }
/* 3650 */       if (volumeId > -1) {
/* 3651 */         stmt.setInt(pos++, volumeId);
/*      */       }
/* 3653 */       rs = stmt.executeQuery();
/* 3654 */       while (rs.next()) {
/* 3655 */         blobs.add(new MailboxBlob.MailboxBlobInfo(null, rs.getInt(1), rs.getInt(2), rs.getInt(3), rs.getString(4), rs.getString(5)));
/*      */       }
/* 3657 */       stmt.close();
/*      */     } finally {
/* 3659 */       DbPool.closeResults(rs);
/*      */     }
/*      */   }
/*      */   
/*      */   private static void getAllBlobs(PreparedStatement stmt, String accountId, int mboxId, SpoolingCache<MailboxBlob.MailboxBlobInfo> blobs) throws SQLException, IOException, ServiceException
/*      */   {
/* 3665 */     ResultSet rs = null;
/*      */     try {
/* 3667 */       int pos = 1;
/* 3668 */       pos = setMailboxId(stmt, mboxId, pos);
/* 3669 */       rs = stmt.executeQuery();
/*      */       
/* 3671 */       while (rs.next()) {
/* 3672 */         blobs.add(new MailboxBlob.MailboxBlobInfo(accountId, mboxId, rs.getInt(1), rs.getInt(2), rs.getString(3), rs.getString(4)));
/*      */       }
/*      */     } finally {
/* 3675 */       DbPool.closeResults(rs);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public static void visitAllBlobDigests(Mailbox mbox, Callback<String> callback)
/*      */     throws ServiceException
/*      */   {
/* 3684 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 3685 */     PreparedStatement stmt = null;
/*      */     try {
/* 3687 */       stmt = conn.prepareStatement("SELECT blob_digest FROM " + getMailItemTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + "blob_digest IS NOT NULL");
/*      */       
/* 3689 */       visitAllBlobDigests(stmt, mbox, callback);
/*      */       
/* 3691 */       stmt = conn.prepareStatement("SELECT blob_digest FROM " + getMailItemTableName(mbox, true) + " WHERE " + IN_THIS_MAILBOX_AND + "blob_digest IS NOT NULL");
/*      */       
/* 3693 */       visitAllBlobDigests(stmt, mbox, callback);
/*      */       
/* 3695 */       stmt = conn.prepareStatement("SELECT blob_digest FROM " + getRevisionTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + "blob_digest IS NOT NULL");
/*      */       
/* 3697 */       visitAllBlobDigests(stmt, mbox, callback);
/*      */       
/* 3699 */       stmt = conn.prepareStatement("SELECT blob_digest FROM " + getRevisionTableName(mbox, true) + " WHERE " + IN_THIS_MAILBOX_AND + "blob_digest IS NOT NULL");
/*      */       
/* 3701 */       visitAllBlobDigests(stmt, mbox, callback);
/*      */     } catch (SQLException e) {
/* 3703 */       throw ServiceException.FAILURE("visiting blob digests list for mailbox " + mbox.getId(), e);
/*      */     } finally {
/* 3705 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   private static void visitAllBlobDigests(PreparedStatement stmt, Mailbox mbox, Callback<String> callback) throws SQLException, ServiceException
/*      */   {
/* 3711 */     ResultSet rs = null;
/*      */     try {
/* 3713 */       int pos = 1;
/* 3714 */       pos = setMailboxId(stmt, mbox, pos);
/* 3715 */       rs = stmt.executeQuery();
/*      */       
/* 3717 */       while (rs.next()) {
/* 3718 */         callback.call(rs.getString(1));
/*      */       }
/*      */     } finally {
/* 3721 */       DbPool.closeResults(rs);
/* 3722 */       stmt.close();
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   public static final int CI_UNREAD = 12;
/*      */   
/*      */   public static final int CI_FLAGS = 13;
/*      */   
/*      */   public static final int CI_TAGS = 14;
/*      */   
/*      */   public static final int CI_SUBJECT = 15;
/*      */   
/*      */   public static final int CI_NAME = 16;
/*      */   
/*      */   public static final int CI_METADATA = 17;
/*      */   
/*      */   public static final int CI_MODIFIED = 18;
/*      */   
/*      */   public static final int CI_MODIFY_DATE = 19;
/*      */   
/*      */   public static final int CI_SAVED = 20;
/*      */   
/*      */   public static final int CI_UUID = 21;
/*      */   
/*      */   static final String DB_FIELDS = "mi.id, mi.type, mi.parent_id, mi.folder_id, mi.prev_folders, mi.index_id,mi.imap_id, mi.date, mi.size, mi.locator, mi.blob_digest, mi.unread, mi.flags, mi.tag_names, mi.subject,mi.name, mi.metadata, mi.mod_metadata, mi.change_date, mi.mod_content, mi.uuid";
/*      */   
/*      */   private static final String REVISION_FIELDS = "date, size, locator, blob_digest, name, metadata, mod_metadata, change_date, mod_content";
/*      */   
/*      */   static MailItem.UnderlyingData constructItem(ResultSet rs)
/*      */     throws SQLException, ServiceException
/*      */   {
/* 3754 */     return constructItem(rs, 0, false);
/*      */   }
/*      */   
/*      */   private static MailItem.UnderlyingData constructItem(ResultSet rs, boolean fromDumpster) throws SQLException, ServiceException {
/* 3758 */     return constructItem(rs, 0, fromDumpster);
/*      */   }
/*      */   
/*      */   static MailItem.UnderlyingData constructItem(ResultSet rs, int offset) throws SQLException, ServiceException {
/* 3762 */     return constructItem(rs, offset, false);
/*      */   }
/*      */   
/*      */   static MailItem.UnderlyingData constructItem(ResultSet rs, int offset, boolean fromDumpster) throws SQLException, ServiceException {
/* 3766 */     MailItem.UnderlyingData data = new MailItem.UnderlyingData();
/* 3767 */     data.id = rs.getInt(1 + offset);
/* 3768 */     data.type = rs.getByte(2 + offset);
/* 3769 */     data.parentId = rs.getInt(3 + offset);
/* 3770 */     data.folderId = rs.getInt(4 + offset);
/* 3771 */     data.setPrevFolders(rs.getString(5 + offset));
/* 3772 */     data.indexId = rs.getInt(6 + offset);
/* 3773 */     if (rs.wasNull()) {
/* 3774 */       data.indexId = MailItem.IndexStatus.NO.id();
/*      */     }
/* 3776 */     data.imapId = rs.getInt(7 + offset);
/* 3777 */     if (rs.wasNull()) {
/* 3778 */       data.imapId = -1;
/*      */     }
/* 3780 */     data.date = rs.getInt(8 + offset);
/* 3781 */     data.size = rs.getLong(9 + offset);
/* 3782 */     data.locator = rs.getString(10 + offset);
/* 3783 */     data.setBlobDigest(rs.getString(11 + offset));
/* 3784 */     data.unreadCount = rs.getInt(12 + offset);
/* 3785 */     int flags = rs.getInt(13 + offset);
/* 3786 */     if (!fromDumpster) {
/* 3787 */       data.setFlags(flags);
/*      */     } else {
/* 3789 */       data.setFlags(flags | Flag.BITMASK_UNCACHED | Flag.BITMASK_IN_DUMPSTER);
/*      */     }
/* 3791 */     data.setTags(new Tag.NormalizedTags(DbTag.deserializeTags(rs.getString(14 + offset))));
/* 3792 */     data.setSubject(rs.getString(15 + offset));
/* 3793 */     data.name = rs.getString(16 + offset);
/* 3794 */     data.metadata = decodeMetadata(rs.getString(17 + offset));
/* 3795 */     data.modMetadata = rs.getInt(18 + offset);
/* 3796 */     data.modContent = rs.getInt(20 + offset);
/* 3797 */     data.dateChanged = rs.getInt(19 + offset);
/*      */     
/* 3799 */     if (data.parentId == 0) {
/* 3800 */       data.parentId = -1;
/*      */     }
/* 3802 */     if (data.dateChanged == 0) {
/* 3803 */       data.dateChanged = -1;
/*      */     }
/* 3805 */     data.uuid = rs.getString(21 + offset);
/* 3806 */     return data;
/*      */   }
/*      */   
/*      */ 
/*      */   private static MailItem.UnderlyingData constructRevision(ResultSet rs, MailItem item, boolean fromDumpster)
/*      */     throws SQLException, ServiceException
/*      */   {
/* 3813 */     MailItem.UnderlyingData data = new MailItem.UnderlyingData();
/* 3814 */     data.id = item.getId();
/* 3815 */     data.type = item.getType().toByte();
/* 3816 */     data.parentId = item.getParentId();
/* 3817 */     data.folderId = item.getFolderId();
/* 3818 */     data.indexId = MailItem.IndexStatus.NO.id();
/* 3819 */     data.imapId = -1;
/* 3820 */     data.date = rs.getInt(1);
/* 3821 */     data.size = rs.getLong(2);
/* 3822 */     data.locator = rs.getString(3);
/* 3823 */     data.setBlobDigest(rs.getString(4));
/* 3824 */     data.unreadCount = item.getUnreadCount();
/* 3825 */     if (!fromDumpster) {
/* 3826 */       data.setFlags(item.getInternalFlagBitmask() | Flag.BITMASK_UNCACHED);
/*      */     } else {
/* 3828 */       data.setFlags(item.getInternalFlagBitmask() | Flag.BITMASK_UNCACHED | Flag.BITMASK_IN_DUMPSTER);
/*      */     }
/* 3830 */     data.setTags(new Tag.NormalizedTags(item.getTags()));
/* 3831 */     data.setSubject(item.getSubject());
/* 3832 */     data.name = rs.getString(5);
/* 3833 */     data.metadata = decodeMetadata(rs.getString(6));
/* 3834 */     data.modMetadata = rs.getInt(7);
/* 3835 */     data.dateChanged = rs.getInt(8);
/* 3836 */     data.modContent = rs.getInt(9);
/*      */     
/* 3838 */     if (data.parentId <= 0) {
/* 3839 */       data.parentId = -1;
/*      */     }
/* 3841 */     if (data.dateChanged == 0) {
/* 3842 */       data.dateChanged = -1;
/*      */     }
/* 3844 */     data.uuid = item.getUuid();
/* 3845 */     return data;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public static MailItem.UnderlyingData getCalendarItem(Mailbox mbox, String uid)
/*      */     throws ServiceException
/*      */   {
/* 3853 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 3854 */     PreparedStatement stmt = null;
/* 3855 */     ResultSet rs = null;
/*      */     try {
/* 3857 */       stmt = conn.prepareStatement("SELECT mi.id, mi.type, mi.parent_id, mi.folder_id, mi.prev_folders, mi.index_id,mi.imap_id, mi.date, mi.size, mi.locator, mi.blob_digest, mi.unread, mi.flags, mi.tag_names, mi.subject,mi.name, mi.metadata, mi.mod_metadata, mi.change_date, mi.mod_content, mi.uuid FROM " + getCalendarItemTableName(mbox, "ci") + ", " + getMailItemTableName(mbox, "mi") + " WHERE ci.uid = ? AND mi.id = ci.item_id AND mi.type IN " + CALENDAR_TYPES + (DebugConfig.disableMailboxGroups ? "" : " AND ci.mailbox_id = ? AND mi.mailbox_id = ci.mailbox_id"));
/*      */       
/*      */ 
/*      */ 
/*      */ 
/* 3862 */       int pos = 1;
/* 3863 */       stmt.setString(pos++, uid);
/* 3864 */       pos = setMailboxId(stmt, mbox, pos);
/* 3865 */       rs = stmt.executeQuery();
/*      */       MailItem.UnderlyingData localUnderlyingData;
/* 3867 */       if (rs.next()) {
/* 3868 */         return constructItem(rs);
/*      */       }
/* 3870 */       return null;
/*      */     } catch (SQLException e) {
/* 3872 */       throw ServiceException.FAILURE("fetching calendar items for mailbox " + mbox.getId(), e);
/*      */     } finally {
/* 3874 */       DbPool.closeResults(rs);
/* 3875 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static List<MailItem.UnderlyingData> getCalendarItems(Mailbox mbox, MailItem.Type type, long start, long end, int folderId, int[] excludeFolderIds)
/*      */     throws ServiceException
/*      */   {
/* 3889 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 3890 */     PreparedStatement stmt = null;
/* 3891 */     ResultSet rs = null;
/*      */     try {
/* 3893 */       stmt = calendarItemStatement(conn, "mi.id, mi.type, mi.parent_id, mi.folder_id, mi.prev_folders, mi.index_id,mi.imap_id, mi.date, mi.size, mi.locator, mi.blob_digest, mi.unread, mi.flags, mi.tag_names, mi.subject,mi.name, mi.metadata, mi.mod_metadata, mi.change_date, mi.mod_content, mi.uuid", mbox, type, start, end, folderId, excludeFolderIds);
/* 3894 */       rs = stmt.executeQuery();
/*      */       
/* 3896 */       List<MailItem.UnderlyingData> result = new ArrayList();
/* 3897 */       while (rs.next()) {
/* 3898 */         result.add(constructItem(rs));
/*      */       }
/* 3900 */       return result;
/*      */     } catch (SQLException e) {
/* 3902 */       throw ServiceException.FAILURE("fetching calendar items for mailbox " + mbox.getId(), e);
/*      */     } finally {
/* 3904 */       DbPool.closeResults(rs);
/* 3905 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static List<MailItem.UnderlyingData> getCalendarItems(Mailbox mbox, List<String> uids) throws ServiceException {
/* 3910 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 3911 */     PreparedStatement stmt = null;
/* 3912 */     ResultSet rs = null;
/* 3913 */     List<MailItem.UnderlyingData> result = new ArrayList();
/*      */     try {
/* 3915 */       for (int i = 0; i < uids.size(); i += Db.getINClauseBatchSize()) {
/* 3916 */         int count = Math.min(Db.getINClauseBatchSize(), uids.size() - i);
/* 3917 */         stmt = conn.prepareStatement("SELECT mi.id, mi.type, mi.parent_id, mi.folder_id, mi.prev_folders, mi.index_id,mi.imap_id, mi.date, mi.size, mi.locator, mi.blob_digest, mi.unread, mi.flags, mi.tag_names, mi.subject,mi.name, mi.metadata, mi.mod_metadata, mi.change_date, mi.mod_content, mi.uuid FROM " + getCalendarItemTableName(mbox, "ci") + ", " + getMailItemTableName(mbox, "mi") + " WHERE mi.id = ci.item_id AND mi.type IN " + CALENDAR_TYPES + (DebugConfig.disableMailboxGroups ? "" : " AND ci.mailbox_id = ? AND mi.mailbox_id = ci.mailbox_id") + " AND " + DbUtil.whereIn("ci.uid", count));
/*      */         
/*      */ 
/*      */ 
/*      */ 
/* 3922 */         int pos = 1;
/* 3923 */         pos = setMailboxId(stmt, mbox, pos);
/* 3924 */         for (int index = i; index < i + count; index++) {
/* 3925 */           stmt.setString(pos++, (String)uids.get(index));
/*      */         }
/* 3927 */         rs = stmt.executeQuery();
/* 3928 */         while (rs.next()) {
/* 3929 */           result.add(constructItem(rs));
/*      */         }
/* 3931 */         stmt.close();
/* 3932 */         stmt = null;
/*      */       }
/* 3934 */       return result;
/*      */     } catch (SQLException e) {
/* 3936 */       throw ServiceException.FAILURE("fetching calendar items for mailbox " + mbox.getId(), e);
/*      */     } finally {
/* 3938 */       DbPool.closeResults(rs);
/* 3939 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public static TypedIdList listCalendarItems(Mailbox mbox, MailItem.Type type, long start, long end, int folderId, int[] excludeFolderIds)
/*      */     throws ServiceException
/*      */   {
/* 3949 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 3950 */     PreparedStatement stmt = null;
/* 3951 */     ResultSet rs = null;
/*      */     try {
/* 3953 */       stmt = calendarItemStatement(conn, "mi.id, mi.type, mi.uuid", mbox, type, start, end, folderId, excludeFolderIds);
/* 3954 */       rs = stmt.executeQuery();
/*      */       
/* 3956 */       TypedIdList result = new TypedIdList();
/* 3957 */       while (rs.next()) {
/* 3958 */         result.add(MailItem.Type.of(rs.getByte(2)), Integer.valueOf(rs.getInt(1)), rs.getString(3));
/*      */       }
/* 3960 */       return result;
/*      */     } catch (SQLException e) {
/* 3962 */       throw ServiceException.FAILURE("listing calendar items for mailbox " + mbox.getId(), e);
/*      */     } finally {
/* 3964 */       DbPool.closeResults(rs);
/* 3965 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private static PreparedStatement calendarItemStatement(DbPool.DbConnection conn, String fields, Mailbox mbox, MailItem.Type type, long start, long end, int folderId, int[] excludeFolderIds)
/*      */     throws SQLException
/*      */   {
/* 3976 */     boolean folderSpecified = folderId != -1;
/*      */     
/*      */ 
/*      */ 
/* 3980 */     String endConstraint = end != -1L ? " AND ci.start_time < ?" : "";
/*      */     
/* 3982 */     String startConstraint = start != -1L ? " AND ci.end_time > ?" : "";
/* 3983 */     String typeConstraint = type == MailItem.Type.UNKNOWN ? "type IN " + CALENDAR_TYPES : typeIn(type);
/*      */     
/* 3985 */     String excludeFolderPart = "";
/* 3986 */     if ((excludeFolderIds != null) && (excludeFolderIds.length > 0)) {
/* 3987 */       excludeFolderPart = " AND " + DbUtil.whereNotIn("folder_id", excludeFolderIds.length);
/*      */     }
/*      */     
/* 3990 */     PreparedStatement stmt = conn.prepareStatement("SELECT " + fields + " FROM " + getCalendarItemTableName(mbox, "ci") + ", " + getMailItemTableName(mbox, "mi") + " WHERE mi.id = ci.item_id" + endConstraint + startConstraint + " AND mi." + typeConstraint + (DebugConfig.disableMailboxGroups ? "" : " AND ci.mailbox_id = ? AND mi.mailbox_id = ci.mailbox_id") + (folderSpecified ? " AND folder_id = ?" : "") + excludeFolderPart);
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 3996 */     int pos = 1;
/* 3997 */     if (!endConstraint.isEmpty()) {
/* 3998 */       stmt.setTimestamp(pos++, new Timestamp(end));
/*      */     }
/* 4000 */     if (!startConstraint.isEmpty()) {
/* 4001 */       stmt.setTimestamp(pos++, new Timestamp(start));
/*      */     }
/* 4003 */     pos = setMailboxId(stmt, mbox, pos);
/* 4004 */     if (folderSpecified) {
/* 4005 */       stmt.setInt(pos++, folderId);
/*      */     }
/* 4007 */     if (excludeFolderIds != null) {
/* 4008 */       for (int id : excludeFolderIds) {
/* 4009 */         stmt.setInt(pos++, id);
/*      */       }
/*      */     }
/*      */     
/* 4013 */     return stmt;
/*      */   }
/*      */   
/*      */   public static void addToCalendarItemTable(CalendarItem calItem) throws ServiceException {
/* 4017 */     Mailbox mbox = calItem.getMailbox();
/*      */     
/* 4019 */     long start = calItem.getStartTime();
/* 4020 */     long end = calItem.getEndTime();
/* 4021 */     Timestamp startTs = new Timestamp(start);
/* 4022 */     Timestamp endTs = getEnd(start, end);
/*      */     
/* 4024 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 4025 */     PreparedStatement stmt = null;
/*      */     try {
/* 4027 */       String mailbox_id = DebugConfig.disableMailboxGroups ? "" : "mailbox_id, ";
/* 4028 */       stmt = conn.prepareStatement("INSERT INTO " + getCalendarItemTableName(mbox) + " (" + mailbox_id + "uid, item_id, start_time, end_time)" + " VALUES (" + (DebugConfig.disableMailboxGroups ? "" : "?, ") + "?, ?, ?, ?)");
/*      */       
/*      */ 
/* 4031 */       int pos = 1;
/* 4032 */       pos = setMailboxId(stmt, mbox, pos);
/* 4033 */       stmt.setString(pos++, calItem.getUid());
/* 4034 */       stmt.setInt(pos++, calItem.getId());
/* 4035 */       stmt.setTimestamp(pos++, startTs);
/* 4036 */       stmt.setTimestamp(pos++, endTs);
/* 4037 */       stmt.executeUpdate();
/*      */     } catch (SQLException e) {
/* 4039 */       throw ServiceException.FAILURE("writing invite to calendar item table: UID=" + calItem.getUid(), e);
/*      */     } finally {
/* 4041 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/* 4045 */   private static long MAX_DATE = new GregorianCalendar(9999, 1, 1).getTimeInMillis();
/*      */   
/*      */   private final Mailbox mailbox;
/*      */   
/*      */   private String sender;
/*      */   
/*      */   private String recipients;
/*      */   
/*      */ 
/*      */   private static Timestamp getEnd(long start, long end)
/*      */   {
/* 4056 */     if ((end <= 0L) && (
/* 4057 */       (end == 0L) || (end == -1L) || (end < start) || (end > start + 31622400000L))) {
/* 4058 */       end = MAX_DATE;
/*      */     }
/*      */     
/* 4061 */     return new Timestamp(end);
/*      */   }
/*      */   
/*      */   public static void updateInCalendarItemTable(CalendarItem calItem) throws ServiceException
/*      */   {
/* 4066 */     Mailbox mbox = calItem.getMailbox();
/* 4067 */     long start = calItem.getStartTime();
/* 4068 */     long end = calItem.getEndTime();
/* 4069 */     Timestamp startTs = new Timestamp(start);
/* 4070 */     Timestamp endTs = getEnd(start, end);
/*      */     
/* 4072 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 4073 */     PreparedStatement stmt = null;
/*      */     try {
/* 4075 */       String command = Db.supports(Db.Capability.REPLACE_INTO) ? "REPLACE" : "INSERT";
/* 4076 */       String mailbox_id = DebugConfig.disableMailboxGroups ? "" : "mailbox_id, ";
/* 4077 */       stmt = conn.prepareStatement(command + " INTO " + getCalendarItemTableName(mbox) + " (" + mailbox_id + "uid, item_id, start_time, end_time)" + " VALUES (" + MAILBOX_ID_VALUE + "?, ?, ?, ?)");
/*      */       
/*      */ 
/* 4080 */       int pos = 1;
/* 4081 */       pos = setMailboxId(stmt, mbox, pos);
/* 4082 */       stmt.setString(pos++, calItem.getUid());
/* 4083 */       stmt.setInt(pos++, calItem.getId());
/* 4084 */       stmt.setTimestamp(pos++, startTs);
/* 4085 */       stmt.setTimestamp(pos++, endTs);
/* 4086 */       stmt.executeUpdate();
/*      */     } catch (SQLException e) {
/* 4088 */       if (Db.errorMatches(e, Db.Error.DUPLICATE_ROW)) {
/*      */         try {
/* 4090 */           DbPool.closeStatement(stmt);
/*      */           
/* 4092 */           stmt = conn.prepareStatement("UPDATE " + getCalendarItemTableName(mbox) + " SET item_id = ?, start_time = ?, end_time = ? WHERE " + IN_THIS_MAILBOX_AND + "uid = ?");
/*      */           
/* 4094 */           int pos = 1;
/* 4095 */           stmt.setInt(pos++, calItem.getId());
/* 4096 */           stmt.setTimestamp(pos++, startTs);
/* 4097 */           stmt.setTimestamp(pos++, endTs);
/* 4098 */           pos = setMailboxId(stmt, mbox, pos);
/* 4099 */           stmt.setString(pos++, calItem.getUid());
/* 4100 */           stmt.executeUpdate();
/*      */         } catch (SQLException nested) {
/* 4102 */           throw ServiceException.FAILURE("updating data in calendar item table " + calItem.getUid(), nested);
/*      */         }
/*      */       } else {
/* 4105 */         throw ServiceException.FAILURE("writing invite to calendar item table " + calItem.getUid(), e);
/*      */       }
/*      */     } finally {
/* 4108 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public static List<CalendarItem.CalendarMetadata> getCalendarItemMetadata(Folder folder, long start, long end)
/*      */     throws ServiceException
/*      */   {
/* 4118 */     Mailbox mbox = folder.getMailbox();
/*      */     
/* 4120 */     ArrayList<CalendarItem.CalendarMetadata> result = new ArrayList();
/*      */     
/* 4122 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 4123 */     PreparedStatement stmt = null;
/* 4124 */     ResultSet rs = null;
/*      */     
/*      */     try
/*      */     {
/* 4128 */       String startConstraint = start != -1L ? " AND ci.end_time > ?" : "";
/*      */       
/* 4130 */       String endConstraint = end != -1L ? " AND ci.start_time < ?" : "";
/* 4131 */       String folderConstraint = " AND mi.folder_id = ?";
/* 4132 */       stmt = conn.prepareStatement("SELECT mi.mailbox_id, mi.id, ci.uid, mi.mod_metadata, mi.mod_content, ci.start_time, ci.end_time FROM " + getMailItemTableName(mbox, "mi") + ", " + getCalendarItemTableName(mbox, "ci") + " WHERE mi.mailbox_id = ci.mailbox_id AND mi.id = ci.item_id" + (DebugConfig.disableMailboxGroups ? "" : " AND mi.mailbox_id = ? ") + startConstraint + endConstraint + folderConstraint);
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 4138 */       int pos = 1;
/* 4139 */       pos = setMailboxId(stmt, mbox, pos);
/* 4140 */       if (!startConstraint.isEmpty()) {
/* 4141 */         stmt.setTimestamp(pos++, new Timestamp(start));
/*      */       }
/* 4143 */       if (!endConstraint.isEmpty()) {
/* 4144 */         stmt.setTimestamp(pos++, new Timestamp(end));
/*      */       }
/* 4146 */       stmt.setInt(pos++, folder.getId());
/* 4147 */       rs = stmt.executeQuery();
/* 4148 */       while (rs.next()) {
/* 4149 */         result.add(new CalendarItem.CalendarMetadata(rs.getInt(1), rs.getInt(2), rs.getString(3), rs.getInt(4), rs.getInt(5), rs.getTimestamp(6).getTime(), rs.getTimestamp(7).getTime()));
/*      */ 
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*      */     }
/*      */     catch (SQLException e)
/*      */     {
/*      */ 
/* 4159 */       throw ServiceException.FAILURE("fetching CalendarItem Metadata for mbox " + mbox.getId(), e);
/*      */     } finally {
/* 4161 */       DbPool.closeResults(rs);
/* 4162 */       DbPool.closeStatement(stmt);
/*      */     }
/* 4164 */     return result; }
/*      */   
/*      */   public static abstract interface Callback<T> { public abstract void call(T paramT); }
/*      */   
/* 4168 */   public static class QueryParams { private final SortedSet<Integer> folderIds = new TreeSet();
/*      */     private Integer dateBefore;
/*      */     private Integer dateAfter;
/*      */     private Integer changeDateBefore;
/*      */     private Integer changeDateAfter;
/*      */     private Integer modifiedSequenceBefore;
/*      */     private Integer rowLimit;
/*      */     private Integer offset;
/*      */     private Flag.FlagInfo flagToExclude;
/* 4177 */     private final Set<MailItem.Type> includedTypes = EnumSet.noneOf(MailItem.Type.class);
/* 4178 */     private final Set<MailItem.Type> excludedTypes = EnumSet.noneOf(MailItem.Type.class);
/* 4179 */     private final List<String> orderBy = new ArrayList();
/*      */     
/*      */     public SortedSet<Integer> getFolderIds() {
/* 4182 */       return Collections.unmodifiableSortedSet(this.folderIds);
/*      */     }
/*      */     
/*      */     public QueryParams setFolderIds(Collection<Integer> ids) {
/* 4186 */       this.folderIds.clear();
/* 4187 */       if (ids != null) {
/* 4188 */         this.folderIds.addAll(ids);
/*      */       }
/* 4190 */       return this;
/*      */     }
/*      */     
/*      */     public Set<MailItem.Type> getIncludedTypes() {
/* 4194 */       return Collections.unmodifiableSet(this.includedTypes);
/*      */     }
/*      */     
/*      */     public QueryParams setIncludedTypes(Collection<MailItem.Type> types) {
/* 4198 */       this.includedTypes.clear();
/* 4199 */       this.includedTypes.addAll(types);
/* 4200 */       return this;
/*      */     }
/*      */     
/*      */     public Set<MailItem.Type> getExcludedTypes() {
/* 4204 */       return Collections.unmodifiableSet(this.excludedTypes);
/*      */     }
/*      */     
/*      */     public QueryParams setExcludedTypes(Collection<MailItem.Type> types) {
/* 4208 */       this.excludedTypes.clear();
/* 4209 */       this.excludedTypes.addAll(types);
/* 4210 */       return this;
/*      */     }
/*      */     
/*      */     public QueryParams setOrderBy(List<String> orders) {
/* 4214 */       this.orderBy.clear();
/* 4215 */       this.orderBy.addAll(orders);
/* 4216 */       return this;
/*      */     }
/*      */     
/*      */     public Integer getDateBefore() {
/* 4220 */       return this.dateBefore;
/*      */     }
/*      */     
/*      */     public void setDateBefore(Integer dateBefore) {
/* 4224 */       this.dateBefore = dateBefore;
/*      */     }
/*      */     
/*      */     public Integer getDateAfter() {
/* 4228 */       return this.dateAfter;
/*      */     }
/*      */     
/*      */     public void setDateAfter(Integer dateAfter) {
/* 4232 */       this.dateAfter = dateAfter;
/*      */     }
/*      */     
/*      */ 
/*      */     public Integer getChangeDateBefore()
/*      */     {
/* 4238 */       return this.changeDateBefore;
/*      */     }
/*      */     
/*      */     public Integer getChangeDateAfter()
/*      */     {
/* 4243 */       return this.changeDateAfter;
/*      */     }
/*      */     
/*      */ 
/*      */     public QueryParams setChangeDateBefore(Integer timestamp)
/*      */     {
/* 4249 */       this.changeDateBefore = timestamp;return this;
/*      */     }
/*      */     
/*      */ 
/*      */     public QueryParams setChangeDateAfter(Integer timestamp)
/*      */     {
/* 4255 */       this.changeDateAfter = timestamp;return this; }
/* 4256 */     public Integer getModifiedSequenceBefore() { return this.modifiedSequenceBefore; }
/* 4257 */     public QueryParams setModifiedSequenceBefore(Integer changeId) { this.modifiedSequenceBefore = changeId;return this; }
/*      */     
/* 4259 */     public Integer getRowLimit() { return this.rowLimit; }
/* 4260 */     public QueryParams setRowLimit(Integer rowLimit) { this.rowLimit = rowLimit;return this; }
/* 4261 */     public Integer getOffset() { return this.offset; }
/* 4262 */     public QueryParams setOffset(Integer offset) { this.offset = offset;return this;
/*      */     }
/*      */     
/* 4265 */     public QueryParams setFlagToExclude(Flag.FlagInfo flag) { this.flagToExclude = flag;
/* 4266 */       return this;
/*      */     }
/*      */     
/*      */     public String getWhereClause() {
/* 4270 */       StringBuilder buf = new StringBuilder();
/* 4271 */       if (!this.includedTypes.isEmpty()) {
/* 4272 */         if (buf.length() > 0) {
/* 4273 */           buf.append(" AND ");
/*      */         }
/* 4275 */         if (this.includedTypes.size() == 1) {
/* 4276 */           Iterator i$ = this.includedTypes.iterator(); if (i$.hasNext()) { MailItem.Type type = (MailItem.Type)i$.next();
/* 4277 */             buf.append("type = ").append(type.toByte());
/*      */           }
/*      */         }
/*      */         else {
/* 4281 */           buf.append("type IN (");
/* 4282 */           boolean first = true;
/* 4283 */           for (MailItem.Type type : this.includedTypes) {
/* 4284 */             if (first) {
/* 4285 */               first = false;
/*      */             } else {
/* 4287 */               buf.append(", ");
/*      */             }
/* 4289 */             buf.append(type.toByte());
/*      */           }
/* 4291 */           buf.append(")");
/*      */         }
/*      */       }
/* 4294 */       if (!this.excludedTypes.isEmpty()) {
/* 4295 */         if (buf.length() > 0) {
/* 4296 */           buf.append(" AND ");
/*      */         }
/* 4298 */         if (this.excludedTypes.size() == 1) {
/* 4299 */           Iterator i$ = this.excludedTypes.iterator(); if (i$.hasNext()) { MailItem.Type type = (MailItem.Type)i$.next();
/* 4300 */             buf.append("type != ").append(type.toByte());
/*      */           }
/*      */         }
/*      */         else {
/* 4304 */           buf.append("type NOT IN (");
/* 4305 */           boolean first = true;
/* 4306 */           for (MailItem.Type type : this.excludedTypes) {
/* 4307 */             if (first) {
/* 4308 */               first = false;
/*      */             } else {
/* 4310 */               buf.append(", ");
/*      */             }
/* 4312 */             buf.append(type.toByte());
/*      */           }
/* 4314 */           buf.append(")");
/*      */         }
/*      */       }
/* 4317 */       if (!this.folderIds.isEmpty()) {
/* 4318 */         if (buf.length() > 0) {
/* 4319 */           buf.append(" AND ");
/*      */         }
/* 4321 */         if (this.folderIds.size() == 1) {
/* 4322 */           buf.append("folder_id = ").append(this.folderIds.first());
/*      */         } else {
/* 4324 */           buf.append("folder_id IN (");
/* 4325 */           boolean first = true;
/* 4326 */           for (Integer fid : this.folderIds) {
/* 4327 */             if (first) {
/* 4328 */               first = false;
/*      */             } else {
/* 4330 */               buf.append(", ");
/*      */             }
/* 4332 */             buf.append(fid);
/*      */           }
/* 4334 */           buf.append(")");
/*      */         }
/*      */       }
/* 4337 */       if (this.dateBefore != null) {
/* 4338 */         if (buf.length() > 0) {
/* 4339 */           buf.append(" AND ");
/*      */         }
/* 4341 */         buf.append("date < ").append(this.dateBefore);
/*      */       }
/* 4343 */       if (this.dateAfter != null) {
/* 4344 */         if (buf.length() > 0) {
/* 4345 */           buf.append(" AND ");
/*      */         }
/* 4347 */         buf.append("date > ").append(this.dateAfter);
/*      */       }
/* 4349 */       if (this.changeDateBefore != null) {
/* 4350 */         if (buf.length() > 0) {
/* 4351 */           buf.append(" AND ");
/*      */         }
/* 4353 */         buf.append("change_date < ").append(this.changeDateBefore);
/*      */       }
/* 4355 */       if (this.changeDateAfter != null) {
/* 4356 */         if (buf.length() > 0) {
/* 4357 */           buf.append(" AND ");
/*      */         }
/* 4359 */         buf.append("change_date > ").append(this.changeDateAfter);
/*      */       }
/* 4361 */       if (this.modifiedSequenceBefore != null) {
/* 4362 */         if (buf.length() > 0) {
/* 4363 */           buf.append(" AND ");
/*      */         }
/* 4365 */         buf.append("mod_metadata < ").append(this.modifiedSequenceBefore);
/*      */       }
/* 4367 */       if (this.flagToExclude != null) {
/* 4368 */         if (buf.length() > 0) {
/* 4369 */           buf.append(" AND ");
/*      */         }
/* 4371 */         buf.append(Db.getInstance().bitAND("flags", String.valueOf(this.flagToExclude.toBitmask()))).append(" != ").append(String.valueOf(this.flagToExclude.toBitmask()));
/*      */       }
/*      */       
/* 4374 */       return buf.toString();
/*      */     }
/*      */     
/*      */     public String getOrderBy() {
/* 4378 */       StringBuilder buf = new StringBuilder();
/* 4379 */       if (!this.orderBy.isEmpty()) {
/* 4380 */         buf.append(" ORDER BY");
/* 4381 */         for (String order : this.orderBy) {
/* 4382 */           buf.append(" ").append(order);
/*      */         }
/*      */       }
/* 4385 */       return buf.toString();
/*      */     }
/*      */     
/*      */     public String getLimitClause() {
/* 4389 */       if ((this.rowLimit != null) && (Db.supports(Db.Capability.LIMIT_CLAUSE))) {
/* 4390 */         if (this.offset != null) {
/* 4391 */           return Db.getInstance().limit(this.offset.intValue(), this.rowLimit.intValue());
/*      */         }
/* 4393 */         return Db.getInstance().limit(this.rowLimit.intValue());
/*      */       }
/*      */       
/* 4396 */       return "";
/*      */     }
/*      */     
/*      */     public String toString()
/*      */     {
/* 4401 */       return getWhereClause() + " " + getOrderBy() + " " + getLimitClause();
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static Set<Integer> getIds(Mailbox mbox, DbPool.DbConnection conn, QueryParams params, boolean fromDumpster)
/*      */     throws ServiceException
/*      */   {
/* 4412 */     PreparedStatement stmt = null;
/* 4413 */     ResultSet rs = null;
/* 4414 */     Set<Integer> ids = new HashSet();
/*      */     
/*      */     try
/*      */     {
/* 4418 */       StringBuilder buf = new StringBuilder();
/* 4419 */       buf.append("SELECT id FROM " + getMailItemTableName(mbox, fromDumpster) + " WHERE " + IN_THIS_MAILBOX_AND);
/* 4420 */       String whereClause = params.getWhereClause();
/* 4421 */       if (!StringUtil.isNullOrEmpty(whereClause)) {
/* 4422 */         buf.append(whereClause);
/*      */       } else {
/* 4424 */         buf.append("1 = 1");
/*      */       }
/* 4426 */       String limitClause = params.getLimitClause();
/* 4427 */       if (!StringUtil.isNullOrEmpty(limitClause)) {
/* 4428 */         buf.append(" ").append(limitClause);
/*      */       }
/* 4430 */       stmt = conn.prepareStatement(buf.toString());
/*      */       
/*      */ 
/* 4433 */       int pos = 1;
/* 4434 */       pos = setMailboxId(stmt, mbox, pos);
/*      */       
/* 4436 */       rs = stmt.executeQuery();
/*      */       
/* 4438 */       while (rs.next()) {
/* 4439 */         ids.add(Integer.valueOf(rs.getInt(1)));
/*      */       }
/* 4441 */       return ids;
/*      */     } catch (SQLException e) {
/* 4443 */       throw ServiceException.FAILURE("getting ids", e);
/*      */     } finally {
/* 4445 */       DbPool.closeResults(rs);
/* 4446 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static List<Integer> getIdsInOrder(Mailbox mbox, DbPool.DbConnection conn, QueryParams params, boolean fromDumpster)
/*      */     throws ServiceException
/*      */   {
/* 4457 */     PreparedStatement stmt = null;
/* 4458 */     ResultSet rs = null;
/* 4459 */     List<Integer> ids = new ArrayList();
/*      */     try
/*      */     {
/* 4462 */       StringBuilder buf = new StringBuilder();
/* 4463 */       buf.append("SELECT id FROM " + getMailItemTableName(mbox, fromDumpster) + " WHERE " + IN_THIS_MAILBOX_AND);
/* 4464 */       String whereClause = params.getWhereClause();
/* 4465 */       if (!StringUtil.isNullOrEmpty(whereClause)) {
/* 4466 */         buf.append(whereClause);
/*      */       } else {
/* 4468 */         buf.append("1 = 1");
/*      */       }
/* 4470 */       String orderBy = params.getOrderBy();
/* 4471 */       if (!StringUtil.isNullOrEmpty(orderBy)) {
/* 4472 */         buf.append(orderBy);
/*      */       }
/* 4474 */       String limitClause = params.getLimitClause();
/* 4475 */       if (!StringUtil.isNullOrEmpty(limitClause)) {
/* 4476 */         buf.append(" ").append(limitClause);
/*      */       }
/* 4478 */       stmt = conn.prepareStatement(buf.toString());
/*      */       
/*      */ 
/* 4481 */       int pos = 1;
/* 4482 */       pos = setMailboxId(stmt, mbox, pos);
/*      */       
/* 4484 */       rs = stmt.executeQuery();
/*      */       
/* 4486 */       while (rs.next()) {
/* 4487 */         ids.add(Integer.valueOf(rs.getInt(1)));
/*      */       }
/* 4489 */       return ids;
/*      */     } catch (SQLException e) {
/* 4491 */       throw ServiceException.FAILURE("getting ids in order", e);
/*      */     } finally {
/* 4493 */       DbPool.closeResults(rs);
/* 4494 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static List<Pair<Integer, Integer>> getDatesAndIdsInOrder(Mailbox mbox, DbPool.DbConnection conn, QueryParams params, boolean fromDumpster)
/*      */     throws ServiceException
/*      */   {
/* 4506 */     PreparedStatement stmt = null;
/* 4507 */     ResultSet rs = null;
/* 4508 */     List<Pair<Integer, Integer>> result = new ArrayList();
/*      */     try
/*      */     {
/* 4511 */       StringBuilder buf = new StringBuilder();
/* 4512 */       buf.append("SELECT date,id FROM " + getMailItemTableName(mbox, fromDumpster) + " WHERE " + IN_THIS_MAILBOX_AND);
/* 4513 */       String whereClause = params.getWhereClause();
/* 4514 */       if (!StringUtil.isNullOrEmpty(whereClause)) {
/* 4515 */         buf.append(whereClause);
/*      */       } else {
/* 4517 */         buf.append("1 = 1");
/*      */       }
/* 4519 */       String orderBy = params.getOrderBy();
/* 4520 */       if (!StringUtil.isNullOrEmpty(orderBy)) {
/* 4521 */         buf.append(orderBy);
/*      */       }
/* 4523 */       String limitClause = params.getLimitClause();
/* 4524 */       if (!StringUtil.isNullOrEmpty(limitClause)) {
/* 4525 */         buf.append(" ").append(limitClause);
/*      */       }
/* 4527 */       stmt = conn.prepareStatement(buf.toString());
/*      */       
/*      */ 
/* 4530 */       int pos = 1;
/* 4531 */       pos = setMailboxId(stmt, mbox, pos);
/*      */       
/* 4533 */       rs = stmt.executeQuery();
/*      */       
/* 4535 */       while (rs.next()) {
/* 4536 */         result.add(new Pair(Integer.valueOf(rs.getInt(1)), Integer.valueOf(rs.getInt(2))));
/*      */       }
/* 4538 */       return result;
/*      */     } catch (SQLException e) {
/* 4540 */       throw ServiceException.FAILURE("getting (change_date,id)s in order", e);
/*      */     } finally {
/* 4542 */       DbPool.closeResults(rs);
/* 4543 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */   public static void consistencyCheck(MailItem item, MailItem.UnderlyingData data, String metadata) throws ServiceException {
/* 4548 */     if (item.getId() <= 0) {
/* 4549 */       return;
/*      */     }
/* 4551 */     Mailbox mbox = item.getMailbox();
/*      */     
/* 4553 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 4554 */     PreparedStatement stmt = null;
/* 4555 */     ResultSet rs = null;
/*      */     try {
/* 4557 */       stmt = conn.prepareStatement("SELECT mi.sender, mi.id, mi.type, mi.parent_id, mi.folder_id, mi.prev_folders, mi.index_id,mi.imap_id, mi.date, mi.size, mi.locator, mi.blob_digest, mi.unread, mi.flags, mi.tag_names, mi.subject,mi.name, mi.metadata, mi.mod_metadata, mi.change_date, mi.mod_content, mi.uuid FROM " + getMailItemTableName(mbox, "mi") + " WHERE " + IN_THIS_MAILBOX_AND + "id = ?");
/*      */       
/*      */ 
/* 4560 */       int pos = 1;
/* 4561 */       pos = setMailboxId(stmt, mbox, pos);
/* 4562 */       stmt.setInt(pos++, item.getId());
/* 4563 */       rs = stmt.executeQuery();
/*      */       
/* 4565 */       if (!rs.next()) {
/* 4566 */         throw ServiceException.FAILURE("consistency check failed: " + item.getType() + " " + item.getId() + " not found in DB", null);
/*      */       }
/*      */       
/*      */ 
/* 4570 */       MailItem.UnderlyingData dbdata = constructItem(rs, 1);
/* 4571 */       String dbsender = rs.getString(1);
/*      */       
/* 4573 */       String dataBlobDigest = data.getBlobDigest();String dbdataBlobDigest = dbdata.getBlobDigest();
/* 4574 */       String dataSender = item.getSortSender();String dbdataSender = dbsender == null ? "" : dbsender;
/* 4575 */       String failures = "";
/*      */       
/* 4577 */       if (data.id != dbdata.id) {
/* 4578 */         failures = failures + " ID";
/*      */       }
/* 4580 */       if (data.type != dbdata.type) {
/* 4581 */         failures = failures + " TYPE";
/*      */       }
/* 4583 */       if (data.folderId != dbdata.folderId) {
/* 4584 */         failures = failures + " FOLDER_ID";
/*      */       }
/* 4586 */       if (StringUtil.equal(data.getPrevFolders(), dbdata.getPrevFolders())) {
/* 4587 */         failures = failures + " PREV_FOLDERS";
/*      */       }
/* 4589 */       if (data.indexId != dbdata.indexId) {
/* 4590 */         failures = failures + " INDEX_ID";
/*      */       }
/* 4592 */       if (data.imapId != dbdata.imapId) {
/* 4593 */         failures = failures + " IMAP_ID";
/*      */       }
/* 4595 */       if (!StringUtil.equal(data.locator, dbdata.locator)) {
/* 4596 */         failures = failures + " LOCATOR";
/*      */       }
/* 4598 */       if (data.date != dbdata.date) {
/* 4599 */         failures = failures + " DATE";
/*      */       }
/* 4601 */       if (data.size != dbdata.size) {
/* 4602 */         failures = failures + " SIZE";
/*      */       }
/* 4604 */       if (dbdata.type != MailItem.Type.CONVERSATION.toByte()) {
/* 4605 */         if (data.unreadCount != dbdata.unreadCount) {
/* 4606 */           failures = failures + " UNREAD";
/*      */         }
/* 4608 */         if (data.getFlags() != dbdata.getFlags()) {
/* 4609 */           failures = failures + " FLAGS";
/*      */         }
/* 4611 */         if (!TagUtil.tagsMatch(data.getTags(), dbdata.getTags())) {
/* 4612 */           failures = failures + " TAGS";
/*      */         }
/*      */       }
/* 4615 */       if (data.modMetadata != dbdata.modMetadata) {
/* 4616 */         failures = failures + " MOD_METADATA";
/*      */       }
/* 4618 */       if (data.dateChanged != dbdata.dateChanged) {
/* 4619 */         failures = failures + " CHANGE_DATE";
/*      */       }
/* 4621 */       if (data.modContent != dbdata.modContent) {
/* 4622 */         failures = failures + " MOD_CONTENT";
/*      */       }
/* 4624 */       if (Math.max(data.parentId, -1) != dbdata.parentId) {
/* 4625 */         failures = failures + " PARENT_ID";
/*      */       }
/* 4627 */       if ((dataBlobDigest != dbdataBlobDigest) && ((dataBlobDigest == null) || (!dataBlobDigest.equals(dbdataBlobDigest)))) {
/* 4628 */         failures = failures + " BLOB_DIGEST";
/*      */       }
/* 4630 */       if ((dataSender != dbdataSender) && ((dataSender == null) || (!dataSender.equalsIgnoreCase(dbdataSender)))) {
/* 4631 */         failures = failures + " SENDER";
/*      */       }
/* 4633 */       if ((data.getSubject() != dbdata.getSubject()) && ((data.getSubject() == null) || (!data.getSubject().equals(dbdata.getSubject()))))
/*      */       {
/* 4635 */         failures = failures + " SUBJECT";
/*      */       }
/* 4637 */       if ((data.name != dbdata.name) && ((data.name == null) || (!data.name.equals(dbdata.name)))) {
/* 4638 */         failures = failures + " NAME";
/*      */       }
/* 4640 */       if ((metadata != dbdata.metadata) && ((metadata == null) || (!metadata.equals(dbdata.metadata)))) {
/* 4641 */         failures = failures + " METADATA";
/*      */       }
/*      */       
/* 4644 */       if (((item instanceof Folder)) && (dbdata.folderId != dbdata.parentId)) {
/* 4645 */         failures = failures + " FOLDER!=PARENT";
/*      */       }
/*      */       
/* 4648 */       if (!failures.equals("")) {
/* 4649 */         throw ServiceException.FAILURE("consistency check failed: " + item.getType() + " " + item.getId() + " differs from DB at" + failures, null);
/*      */       }
/*      */     }
/*      */     catch (SQLException e) {
/* 4653 */       throw ServiceException.FAILURE("fetching item " + item.getId(), e);
/*      */     } finally {
/* 4655 */       DbPool.closeResults(rs);
/* 4656 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static String normalize(String value, int max)
/*      */   {
/* 4671 */     if (Strings.isNullOrEmpty(value)) {
/* 4672 */       return value;
/*      */     }
/* 4674 */     String trimmed = value.length() <= max ? value : value.substring(0, max).trim();
/* 4675 */     if (!Db.supports(Db.Capability.NON_BMP_CHARACTERS)) {
/* 4676 */       trimmed = StringUtil.removeSurrogates(trimmed);
/*      */     }
/* 4678 */     return trimmed;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static String checkMetadataLength(String metadata)
/*      */     throws ServiceException
/*      */   {
/* 4690 */     if (metadata == null) {
/* 4691 */       return null;
/*      */     }
/*      */     
/* 4694 */     String result = encodeMetadata(metadata);
/* 4695 */     int len = result.length();
/* 4696 */     if (len > 4194304) {
/* 4697 */       if (StringUtil.isAsciiString(result)) {
/* 4698 */         if (len > 16777216) {
/* 4699 */           throw ServiceException.FAILURE("metadata too long", null);
/*      */         }
/*      */       } else {
/*      */         try {
/* 4703 */           if (result.getBytes("utf-8").length > 16777216) {
/* 4704 */             throw ServiceException.FAILURE("metadata too long", null);
/*      */           }
/*      */         } catch (UnsupportedEncodingException uee) {}
/*      */       }
/*      */     }
/* 4709 */     return result;
/*      */   }
/*      */   
/*      */   public static String encodeMetadata(String metadata) throws ServiceException {
/* 4713 */     if ((Db.supports(Db.Capability.NON_BMP_CHARACTERS)) || (!StringUtil.containsSurrogates(metadata))) {
/* 4714 */       return metadata;
/*      */     }
/*      */     try
/*      */     {
/* 4718 */       return new BCodec("utf-8").encode(metadata);
/*      */     } catch (EncoderException ee) {
/* 4720 */       throw ServiceException.FAILURE("encoding non-BMP metadata", ee);
/*      */     }
/*      */   }
/*      */   
/*      */   public static String decodeMetadata(String metadata) throws ServiceException {
/* 4725 */     if ((StringUtil.isNullOrEmpty(metadata)) || (!metadata.startsWith("=?"))) {
/* 4726 */       return metadata;
/*      */     }
/*      */     try {
/* 4729 */       return new BCodec("utf-8").decode(metadata);
/*      */     } catch (DecoderException de) {
/* 4731 */       throw ServiceException.FAILURE("encoding non-BMP metadata", de);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static String getMailItemTableName(int groupId, boolean dumpster)
/*      */   {
/* 4741 */     return DbMailbox.qualifyTableName(groupId, !dumpster ? "mail_item" : "mail_item_dumpster");
/*      */   }
/*      */   
/* 4744 */   public static String getMailItemTableName(MailItem item) { return getMailItemTableName(item, false); }
/*      */   
/*      */   public static String getMailItemTableName(MailItem item, boolean dumpster) {
/* 4747 */     return DbMailbox.qualifyTableName(item.getMailbox(), !dumpster ? "mail_item" : "mail_item_dumpster");
/*      */   }
/*      */   
/* 4750 */   public static String getMailItemTableName(Mailbox mbox) { return getMailItemTableName(mbox, false); }
/*      */   
/*      */   public static String getMailItemTableName(Mailbox mbox, boolean dumpster) {
/* 4753 */     return DbMailbox.qualifyTableName(mbox, !dumpster ? "mail_item" : "mail_item_dumpster");
/*      */   }
/*      */   
/* 4756 */   public static String getMailItemTableName(Mailbox mbox, String alias) { return getMailItemTableName(mbox, alias, false); }
/*      */   
/*      */   public static String getMailItemTableName(Mailbox mbox, String alias, boolean dumpster) {
/* 4759 */     return getMailItemTableName(mbox, dumpster) + " AS " + alias;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public static String getRevisionTableName(int groupId, boolean dumpster)
/*      */   {
/* 4767 */     return DbMailbox.qualifyTableName(groupId, !dumpster ? "revision" : "revision_dumpster");
/*      */   }
/*      */   
/* 4770 */   public static String getRevisionTableName(MailItem item) { return getRevisionTableName(item, false); }
/*      */   
/*      */   public static String getRevisionTableName(MailItem item, boolean dumpster) {
/* 4773 */     return DbMailbox.qualifyTableName(item.getMailbox(), !dumpster ? "revision" : "revision_dumpster");
/*      */   }
/*      */   
/* 4776 */   public static String getRevisionTableName(Mailbox mbox) { return getRevisionTableName(mbox, false); }
/*      */   
/*      */   public static String getRevisionTableName(Mailbox mbox, boolean dumpster) {
/* 4779 */     return DbMailbox.qualifyTableName(mbox, !dumpster ? "revision" : "revision_dumpster");
/*      */   }
/*      */   
/* 4782 */   public static String getRevisionTableName(Mailbox mbox, String alias) { return getRevisionTableName(mbox, alias, false); }
/*      */   
/*      */   public static String getRevisionTableName(Mailbox mbox, String alias, boolean dumpster) {
/* 4785 */     return getRevisionTableName(mbox, dumpster) + " AS " + alias;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public static String getCalendarItemTableName(int mailboxId, int groupId, boolean dumpster)
/*      */   {
/* 4793 */     return DbMailbox.qualifyTableName(groupId, !dumpster ? "appointment" : "appointment_dumpster");
/*      */   }
/*      */   
/* 4796 */   public static String getCalendarItemTableName(Mailbox mbox) { return getCalendarItemTableName(mbox, false); }
/*      */   
/*      */   public static String getCalendarItemTableName(Mailbox mbox, boolean dumpster) {
/* 4799 */     return DbMailbox.qualifyTableName(mbox, !dumpster ? "appointment" : "appointment_dumpster");
/*      */   }
/*      */   
/* 4802 */   public static String getCalendarItemTableName(Mailbox mbox, String alias) { return getCalendarItemTableName(mbox, alias, false); }
/*      */   
/*      */   public static String getCalendarItemTableName(Mailbox mbox, String alias, boolean dumpster) {
/* 4805 */     return getCalendarItemTableName(mbox, dumpster) + " AS " + alias;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public static String getConversationTableName(int mailboxId, int groupId)
/*      */   {
/* 4813 */     return DbMailbox.qualifyTableName(groupId, "open_conversation");
/*      */   }
/*      */   
/* 4816 */   public static String getConversationTableName(MailItem item) { return DbMailbox.qualifyTableName(item.getMailbox(), "open_conversation"); }
/*      */   
/*      */   public static String getConversationTableName(Mailbox mbox) {
/* 4819 */     return DbMailbox.qualifyTableName(mbox, "open_conversation");
/*      */   }
/*      */   
/* 4822 */   public static String getConversationTableName(Mailbox mbox, String alias) { return getConversationTableName(mbox) + " AS " + alias; }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static String getTombstoneTableName(int mailboxId, int groupId)
/*      */   {
/* 4830 */     return DbMailbox.qualifyTableName(groupId, "tombstone");
/*      */   }
/*      */   
/* 4833 */   public static String getTombstoneTableName(Mailbox mbox) { return DbMailbox.qualifyTableName(mbox, "tombstone"); }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   static String getIdListForLogging(Collection<Integer> ids)
/*      */   {
/* 4841 */     if (ids == null) {
/* 4842 */       return null;
/*      */     }
/* 4844 */     StringBuilder idList = new StringBuilder();
/* 4845 */     boolean firstTime = true;
/* 4846 */     for (Integer id : ids) {
/* 4847 */       if (firstTime) {
/* 4848 */         firstTime = false;
/*      */       } else {
/* 4850 */         idList.append(',');
/*      */       }
/* 4852 */       idList.append(id);
/* 4853 */       if (idList.length() > 200) {
/* 4854 */         idList.append("...");
/* 4855 */         break;
/*      */       }
/*      */     }
/* 4858 */     return idList.toString();
/*      */   }
/*      */   
/*      */   public static TypedIdList listItems(Folder folder, long messageSyncStart, MailItem.Type type, boolean descending, boolean older) throws ServiceException {
/* 4862 */     Mailbox mbox = folder.getMailbox();
/* 4863 */     assert ((Db.supports(Db.Capability.ROW_LEVEL_LOCKING)) || (Thread.holdsLock(mbox)));
/*      */     
/* 4865 */     TypedIdList result = new TypedIdList();
/* 4866 */     DbPool.DbConnection conn = mbox.getOperationConnection();
/* 4867 */     PreparedStatement stmt = null;
/* 4868 */     ResultSet rs = null;
/*      */     try {
/* 4870 */       if (older) {
/* 4871 */         stmt = conn.prepareStatement("SELECT id, type, uuid FROM " + getMailItemTableName(folder) + " WHERE " + IN_THIS_MAILBOX_AND + " type = ? AND folder_id = ? AND date < ?" + " ORDER BY date" + (descending ? " DESC" : ""));
/*      */       }
/*      */       else
/*      */       {
/* 4875 */         stmt = conn.prepareStatement("SELECT id, type, uuid FROM " + getMailItemTableName(folder) + " WHERE " + IN_THIS_MAILBOX_AND + " type = ? AND folder_id = ? AND date >= ?" + " ORDER BY date" + (descending ? " DESC" : ""));
/*      */       }
/*      */       
/*      */ 
/* 4879 */       int pos = 1;
/* 4880 */       pos = setMailboxId(stmt, mbox, pos);
/* 4881 */       stmt.setByte(pos++, type.toByte());
/* 4882 */       stmt.setInt(pos++, folder.getId());
/* 4883 */       stmt.setLong(pos++, messageSyncStart);
/* 4884 */       rs = stmt.executeQuery();
/*      */       MailItem.Type dataType;
/* 4886 */       while (rs.next()) {
/* 4887 */         dataType = MailItem.Type.of(rs.getByte(2));
/* 4888 */         result.add(dataType, Integer.valueOf(rs.getInt(1)), rs.getString(3));
/*      */       }
/* 4890 */       return result;
/*      */     } catch (SQLException e) {
/* 4892 */       throw ServiceException.FAILURE("fetching item list for folder " + folder.getId(), e);
/*      */     } finally {
/* 4894 */       DbPool.closeResults(rs);
/* 4895 */       DbPool.closeStatement(stmt);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public DbMailItem(Mailbox mbox)
/*      */   {
/* 4908 */     this.mailbox = mbox;
/*      */   }
/*      */   
/*      */   public DbMailItem setSender(String value) {
/* 4912 */     if (!Strings.isNullOrEmpty(value)) {
/* 4913 */       this.sender = normalize(value, 128);
/*      */     }
/* 4915 */     return this;
/*      */   }
/*      */   
/*      */   public DbMailItem setRecipients(String value) {
/* 4919 */     if (!Strings.isNullOrEmpty(value)) {
/* 4920 */       this.recipients = normalize(value, 128);
/*      */     }
/* 4922 */     return this;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static void assignUuids(Mailbox mbox, boolean reassignExisting)
/*      */     throws ServiceException
/*      */   {
/* 4937 */     String types = "type IN (1, 2, 8, 13, 14, 17, 18)";
/*      */     String[] tables;
/*      */     String[] tables;
/* 4940 */     if (Db.supports(Db.Capability.DUMPSTER_TABLES)) {
/* 4941 */       tables = new String[] { getMailItemTableName(mbox, false), getMailItemTableName(mbox, true) };
/*      */     } else {
/* 4943 */       tables = new String[] { getMailItemTableName(mbox, false) };
/*      */     }
/* 4945 */     DbPool.DbConnection conn = null;
/*      */     try {
/* 4947 */       conn = DbPool.getConnection(mbox);
/* 4948 */       if (reassignExisting) {
/* 4949 */         for (String table : tables) {
/* 4950 */           PreparedStatement clear = null;
/*      */           try {
/* 4952 */             clear = conn.prepareStatement("UPDATE " + table + " SET uuid = NULL" + " WHERE " + IN_THIS_MAILBOX_AND + " uuid IS NOT NULL");
/*      */             
/* 4954 */             setMailboxId(clear, mbox, 1);
/* 4955 */             clear.execute();
/* 4956 */             conn.commit();
/*      */           } catch (SQLException e) {
/* 4958 */             throw ServiceException.FAILURE("error while clearing existing uuid values", e);
/*      */           } finally {
/* 4960 */             conn.closeQuietly(clear);
/*      */           }
/*      */         }
/*      */       }
/* 4964 */       for (String table : tables) {
/* 4965 */         boolean done = false;
/* 4966 */         int batchSize = 1000;
/* 4967 */         while (!done)
/*      */         {
/* 4969 */           PreparedStatement stmt = null;
/* 4970 */           ResultSet rs = null;
/* 4971 */           List<Integer> ids = new ArrayList(batchSize);
/*      */           try {
/* 4973 */             stmt = conn.prepareStatement("SELECT id FROM " + table + " WHERE " + IN_THIS_MAILBOX_AND + types + " AND uuid IS NULL LIMIT ?");
/*      */             
/* 4975 */             int pos = setMailboxId(stmt, mbox, 1);
/* 4976 */             stmt.setInt(pos, batchSize);
/* 4977 */             rs = stmt.executeQuery();
/* 4978 */             while (rs.next()) {
/* 4979 */               ids.add(Integer.valueOf(rs.getInt(1)));
/*      */             }
/*      */           } catch (SQLException e) {
/* 4982 */             throw ServiceException.FAILURE("error while fetching rows with missing uuid", e);
/*      */           } finally {
/* 4984 */             conn.closeQuietly(rs);
/* 4985 */             conn.closeQuietly(stmt);
/*      */           }
/*      */           
/* 4988 */           for (Iterator i$ = ids.iterator(); i$.hasNext();) { int id = ((Integer)i$.next()).intValue();
/* 4989 */             PreparedStatement update = null;
/*      */             try {
/* 4991 */               update = conn.prepareStatement("UPDATE " + table + " SET uuid = ?" + " WHERE " + IN_THIS_MAILBOX_AND + " id = ?");
/*      */               
/* 4993 */               int pos = 1;
/* 4994 */               update.setString(pos++, UUIDUtil.generateUUID());
/* 4995 */               pos = setMailboxId(update, mbox, pos);
/* 4996 */               update.setInt(pos, id);
/* 4997 */               update.execute();
/*      */             } catch (SQLException e) {
/* 4999 */               throw ServiceException.FAILURE("error while setting uuid for item " + id, e);
/*      */             } finally {
/* 5001 */               conn.closeQuietly(update);
/*      */             }
/*      */           }
/*      */           
/* 5005 */           conn.commit();
/* 5006 */           done = ids.isEmpty();
/*      */         }
/*      */       }
/*      */     }
/*      */     catch (ServiceException e) {
/* 5011 */       throw e;
/*      */     } finally {
/* 5013 */       DbPool.quietClose(conn);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static List<Integer> getIMAPDeletedItems(Mailbox mbox, long cutOff, int batchSize)
/*      */     throws ServiceException
/*      */   {
/* 5025 */     List<Integer> imapDeletedItems = new ArrayList();
/* 5026 */     DbPool.DbConnection conn = null;
/* 5027 */     PreparedStatement stmt = null;
/* 5028 */     ResultSet rs = null;
/*      */     try {
/* 5030 */       conn = DbPool.getConnection(mbox);
/* 5031 */       stmt = conn.prepareStatement("SELECT id FROM " + getMailItemTableName(mbox) + " WHERE " + IN_THIS_MAILBOX_AND + " change_date < ? AND " + Db.getInstance().bitAND("flags", String.valueOf(Flag.BITMASK_DELETED)) + " = " + String.valueOf(Flag.BITMASK_DELETED) + " limit " + batchSize);
/*      */       
/*      */ 
/*      */ 
/* 5035 */       setMailboxId(stmt, mbox, 1);
/* 5036 */       stmt.setLong(2, cutOff);
/* 5037 */       rs = stmt.executeQuery();
/* 5038 */       while (rs.next()) {
/* 5039 */         imapDeletedItems.add(Integer.valueOf(rs.getInt("id")));
/*      */       }
/*      */     } catch (SQLException sqle) {
/* 5042 */       throw ServiceException.FAILURE("error while fetching imap deleted items", sqle);
/*      */     } finally {
/* 5044 */       conn.closeQuietly(rs);
/* 5045 */       conn.closeQuietly(stmt);
/* 5046 */       DbPool.quietClose(conn);
/*      */     }
/* 5048 */     return imapDeletedItems;
/*      */   }
/*      */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/db/DbMailItem.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */